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
b434f1fbf4 Merge pull request #67 from IBM/cleue-add-flap-to-reader
fix: add flap to Reader
2023-10-11 22:24:00 +02:00
Dr. Carsten Leue
756e1336dc fix: add flap to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-11 22:23:19 +02:00
Carsten Leue
c629d18bb3 Merge pull request #66 from IBM/cleue-add-try-catch-for-single-value-return
fix: remove File.GetName and add Join for convenience
2023-10-11 21:25:17 +02:00
Dr. Carsten Leue
1eefc28ba6 fix: remove File.GetName and add Join for convenience
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-11 17:36:11 +02:00
Carsten Leue
af2915d98a Merge pull request #65 from IBM/cleue-fix-flap-order
fix: change order of generics for flap
2023-10-10 22:41:43 +02:00
Dr. Carsten Leue
e9f9c2777f fix: change order of generics for flap
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-10 22:40:59 +02:00
Carsten Leue
895862a67e Merge pull request #64 from IBM/cleue-add-FromReaderIO
fix: add missing RightReaderIO and FromReaderIO to context
2023-10-10 15:05:34 +02:00
Dr. Carsten Leue
caf0574742 fix: add missing RightReaderIO and FromReaderIO to context
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-10 15:04:59 +02:00
Carsten Leue
bace6f01eb Merge pull request #62 from IBM/cleue-add-missing-chain-readeriok
fix: add missing ChainReaderIOK
2023-10-06 23:03:16 +02:00
Dr. Carsten Leue
254c63a16f fix: add missing ChainReaderIOK
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 23:02:45 +02:00
Carsten Leue
655c8a9b1d Merge pull request #61 from IBM/cleue-add-chain-first-to-readerio
fix: add missing ChainXXIOK to Reader
2023-10-06 22:36:38 +02:00
Dr. Carsten Leue
c6d6be66e0 fix: add missing ChainXXIOK to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 22:36:04 +02:00
Carsten Leue
e313f95865 Merge pull request #60 from IBM/cleue-alternative-monoid-for-option
fix: provide AltMonoid
2023-10-06 21:50:57 +02:00
Dr. Carsten Leue
5f25317f97 fix: provide AltMonoid
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-10-06 21:50:22 +02:00
Carsten Leue
f5aa2d6c15 Merge pull request #58 from IBM/renovate/major-go-dependencies
chore(deps): update actions/checkout action to v4
2023-10-05 15:20:29 +02:00
renovate[bot]
7262820624 chore(deps): update actions/checkout action to v4 2023-10-05 12:37:09 +00:00
Carsten Leue
c8fc10358b Merge pull request #56 from IBM/cleue-add-flap
fix: add flap and non empty array
2023-09-26 22:33:30 +02:00
Dr. Carsten Leue
1cd167541d fix: add flap and non empty array
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-26 22:32:53 +02:00
Carsten Leue
ebe94d71dc Merge pull request #55 from IBM/sample-match
fix: add match example
2023-09-24 22:17:05 +02:00
Dr. Carsten Leue
7ef6eb524b fix: add match example
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-24 22:15:01 +02:00
Carsten Leue
7b82e87bf3 Merge pull request #53 from IBM/cleue-add-missing-flatten-to-reader
fix: add missing Flatten to Reader
2023-09-20 17:54:07 +02:00
Dr. Carsten Leue
e8fdbe9f87 fix: add missing Flatten to Reader
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-20 17:53:45 +02:00
Carsten Leue
226c7039de Merge pull request #52 from IBM/cleue-add-memoize-to-reader
fix: add missing Memoize to readers
2023-09-20 16:04:51 +02:00
Dr. Carsten Leue
943ae8e009 fix: add missing Memoize to readers
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-20 15:56:02 +02:00
Carsten Leue
44c8441b07 Merge pull request #51 from IBM/cleue-rioe-tests
fix: add RIOE testcases
2023-09-19 22:33:56 +02:00
Dr. Carsten Leue
600aeae770 fix: add RIOE testcases
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 22:31:55 +02:00
Carsten Leue
f74a407294 Merge pull request #50 from IBM/cleue-add-some-tweaks
fix: add WithTempFile to ReaderIOEither
2023-09-19 18:07:06 +02:00
Dr. Carsten Leue
b15ab38861 fix: add WithTempFile to ReaderIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 18:06:32 +02:00
Carsten Leue
6532a83e82 Merge pull request #49 from IBM/cleue-add-ioeither-sample-with-return-tuple
fix: add missing IOO.FromIOEither
2023-09-19 12:29:23 +02:00
Dr. Carsten Leue
7c12b72db1 fix: add missing IOO.FromIOEither
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 12:24:05 +02:00
Carsten Leue
dc894ad643 Merge pull request #48 from IBM/cleue-some-benchmarking
fix: add some benchmarks
2023-09-19 10:22:04 +02:00
Dr. Carsten Leue
c902058320 fix: add some benchmarks
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-19 10:21:16 +02:00
Carsten Leue
bf33f4fb66 Merge pull request #46 from a-lipson/main
Modified doc for generateTupled functions (& changed occurences)
2023-09-19 10:12:57 +02:00
Dre
b4d2a5c6be fixed typo in ioeither ChainFirstIOK doc line 2023-09-18 15:48:00 -07:00
a-lipson
705b71d95c Modified doc for generateTupled functions (& changed occurences) 2023-09-15 17:01:11 -07:00
Carsten Leue
34844bcfc2 Merge pull request #45 from IBM/cleue-prefer-second-over-SK
doc: ad doc to SK function
2023-09-13 15:04:50 +02:00
Dr. Carsten Leue
9a9d13b066 doc: ad doc to SK function
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-13 15:04:19 +02:00
Carsten Leue
da1449e680 Merge pull request #44 from IBM/cleue-add-apply-monoid
fix: add missing alt methods and semigroup
2023-09-12 22:16:20 +02:00
Dr. Carsten Leue
865d9fe064 fix: add missing alt methods and semigroup
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 22:10:33 +02:00
Carsten Leue
c5b1bae65a Merge pull request #43 from IBM/cleue-add-custom-type-sample
Cleue add custom type sample
2023-09-12 13:47:12 +02:00
Dr. Carsten Leue
0a395f63ff fix: merge
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 13:45:07 +02:00
Dr. Carsten Leue
26a7066de0 fix: add UnslicedN
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 13:28:23 +02:00
Dr. Carsten Leue
52823e2c8e fix: add UnslicedN
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-12 10:52:39 +02:00
Carsten Leue
503021c65e Merge pull request #42 from IBM/cleue-add-traverse-with-index
fix: add missing withIndex methods
2023-09-11 13:50:30 +02:00
Dr. Carsten Leue
a2a6a41993 fix: add missing withIndex methods
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-11 13:48:51 +02:00
Carsten Leue
7da9de6f41 Merge pull request #41 from IBM/cleue-add-missing-functions
fix: order of parameters in optics
2023-09-10 21:56:23 +02:00
Dr. Carsten Leue
ff1b6faf84 fix: order of parameters in optics
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-10 21:49:44 +02:00
Carsten Leue
38120764e7 Merge pull request #40 from IBM/cleue-add-missing-lenses
fix: change Cache to Memoize and fix order of parameters to ToType
2023-09-10 21:37:38 +02:00
Dr. Carsten Leue
a83c2aec49 fix: change Cache to Memoize and fix order of parameters to ToType
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-10 21:29:01 +02:00
Carsten Leue
03debd37c8 Merge pull request #39 from IBM/cleue-implement-compact
fix: add compact methods
2023-09-08 22:57:18 +02:00
Dr. Carsten Leue
4f04344cda fix: add compact methods
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 22:54:58 +02:00
Carsten Leue
cf1c886f48 Merge pull request #37 from IBM/cleue-fix-order-of-generics-for-ChainOptionK
fix: order of generic parameters
2023-09-08 18:18:36 +02:00
Dr. Carsten Leue
3e0eb99b88 fix: order of generic parameters
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 18:16:06 +02:00
Carsten Leue
cb15a3d9fc Merge pull request #36 from IBM/cleue-mostly-adequate-more-samples
Cleue mostly adequate more samples
2023-09-08 15:31:01 +02:00
Dr. Carsten Leue
16535605f5 fix: add better sequence and traverse for option and either
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 15:26:56 +02:00
Dr. Carsten Leue
53f4e5ebd7 fix: add more mostly-adequate examples and solutions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-08 15:25:44 +02:00
Dr. Carsten Leue
fb91fd5dc8 fix: add more mostly-adequate examples and solutions
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2023-09-07 17:21:39 +02:00
144 changed files with 3197 additions and 193 deletions

View File

@@ -29,7 +29,7 @@ jobs:
go-version: [ '1.20.x', '1.21.x' ] go-version: [ '1.20.x', '1.21.x' ]
steps: steps:
# full checkout for semantic-release # full checkout for semantic-release
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with: with:
fetch-depth: 0 fetch-depth: 0
- name: Set up go ${{ matrix.go-version }} - name: Set up go ${{ matrix.go-version }}
@@ -55,7 +55,7 @@ jobs:
steps: steps:
# full checkout for semantic-release # full checkout for semantic-release
- name: Full checkout - name: Full checkout
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
with: with:
fetch-depth: 0 fetch-depth: 0

View File

@@ -14,6 +14,8 @@ go get github.com/IBM/fp-go
Refer to the [samples](./samples/). Refer to the [samples](./samples/).
Find API documentation [here](https://pkg.go.dev/github.com/IBM/fp-go)
## Design Goal ## Design Goal
This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns: This library aims to provide a set of data types and functions that make it easy and fun to write maintainable and testable code in golang. It encourages the following patterns:
@@ -192,3 +194,14 @@ this would be the completely generic method signature for all possible monads. I
This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability. This FP library addresses this by introducing the HKTs as individual types, e.g. `HKT[A]` would be represented as a new generic type `HKTA`. This loses the correlation to the type `A` but allows to implement generic algorithms, at the price of readability.
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users. For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
## Map/Ap/Flap
The following table lists the relationship between some selected operators
| Opertator | Parameter | Monad | Result |
| -------- | ---------------- | --------------- | -------- |
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` |
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` |
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` |
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` |

View File

@@ -308,3 +308,11 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
func Push[A any](a A) func([]A) []A { func Push[A any](a A) func([]A) []A {
return G.Push[[]A](a) return G.Push[[]A](a)
} }
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
}
func Flap[B, A any](a A) func([]func(A) B) []B {
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
}

View File

@@ -18,6 +18,7 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array" "github.com/IBM/fp-go/internal/array"
FC "github.com/IBM/fp-go/internal/functor"
M "github.com/IBM/fp-go/monoid" M "github.com/IBM/fp-go/monoid"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
"github.com/IBM/fp-go/tuple" "github.com/IBM/fp-go/tuple"
@@ -187,6 +188,14 @@ func IsEmpty[AS ~[]A, A any](as AS) bool {
return array.IsEmpty(as) return array.IsEmpty(as)
} }
func IsNil[GA ~[]A, A any](as GA) bool {
return array.IsNil(as)
}
func IsNonNil[GA ~[]A, A any](as GA) bool {
return array.IsNonNil(as)
}
func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B { func Match[AS ~[]A, A, B any](onEmpty func() B, onNonEmpty func(AS) B) func(AS) B {
return func(as AS) B { return func(as AS) B {
if IsEmpty(as) { if IsEmpty(as) {
@@ -242,3 +251,11 @@ func Fold[AS ~[]A, A any](m M.Monoid[A]) func(AS) A {
func Push[GA ~[]A, A any](a A) func(GA) GA { func Push[GA ~[]A, A any](a A) func(GA) GA {
return F.Bind2nd(array.Push[GA, A], a) return F.Bind2nd(array.Push[GA, A], a)
} }
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
}
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
}

124
array/nonempty/array.go Normal file
View File

@@ -0,0 +1,124 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package nonempty
import (
G "github.com/IBM/fp-go/array/generic"
F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/array"
S "github.com/IBM/fp-go/semigroup"
)
// NonEmptyArray represents an array with at least one element
type NonEmptyArray[A any] []A
// Of constructs a single element array
func Of[A any](first A) NonEmptyArray[A] {
return G.Of[NonEmptyArray[A]](first)
}
// From constructs a [NonEmptyArray] from a set of variadic arguments
func From[A any](first A, data ...A) NonEmptyArray[A] {
count := len(data)
if count == 0 {
return Of(first)
}
// allocate the requested buffer
buffer := make(NonEmptyArray[A], count+1)
buffer[0] = first
copy(buffer[1:], data)
return buffer
}
func IsEmpty[A any](as NonEmptyArray[A]) bool {
return false
}
func IsNonEmpty[A any](as NonEmptyArray[A]) bool {
return true
}
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
}
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
return F.Bind2nd(MonadMap[A, B], f)
}
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(as, f, initial)
}
}
func Tail[A any](as NonEmptyArray[A]) []A {
return as[1:]
}
func Head[A any](as NonEmptyArray[A]) A {
return as[0]
}
func First[A any](as NonEmptyArray[A]) A {
return as[0]
}
func Last[A any](as NonEmptyArray[A]) A {
return as[len(as)-1]
}
func Size[A any](as NonEmptyArray[A]) int {
return G.Size(as)
}
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
return G.Flatten(mma)
}
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
}
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
}
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
return G.MonadAp[NonEmptyArray[B]](fab, fa)
}
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
}
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
return func(f func(A) B) func(NonEmptyArray[A]) B {
return func(as NonEmptyArray[A]) B {
return array.Reduce(Tail(as), func(cur B, a A) B {
return s.Concat(cur, f(a))
}, f(Head(as)))
}
}
}
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
return func(as NonEmptyArray[A]) A {
return array.Reduce(Tail(as), s.Concat, Head(as))
}
}

View File

@@ -25,6 +25,40 @@ import (
C "github.com/urfave/cli/v2" C "github.com/urfave/cli/v2"
) )
func generateUnsliced(f *os.File, i int) {
// Create the optionize version
fmt.Fprintf(f, "\n// Unsliced%d converts a function taking a slice parameter into a function with %d parameters\n", i, i)
fmt.Fprintf(f, "func Unsliced%d[F ~func([]T) R, T, R any](f F) func(", i)
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return func(")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
if i > 0 {
fmt.Fprintf(f, " T")
}
fmt.Fprintf(f, ") R {\n")
fmt.Fprintf(f, " return f([]T{")
for j := 0; j < i; j++ {
if j > 0 {
fmt.Fprintf(f, ", ")
}
fmt.Fprintf(f, "t%d", j+1)
}
fmt.Fprintln(f, "})")
fmt.Fprintln(f, " }")
fmt.Fprintln(f, "}")
}
func generateVariadic(f *os.File, i int) { func generateVariadic(f *os.File, i int) {
// Create the nullary version // Create the nullary version
fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i) fmt.Fprintf(f, "\n// Variadic%d converts a function taking %d parameters and a final slice into a function with %d parameters but a final variadic argument\n", i, i, i)
@@ -83,7 +117,7 @@ func generateVariadic(f *os.File, i int) {
fmt.Fprintf(f, "v)\n") fmt.Fprintf(f, "v)\n")
fmt.Fprintf(f, " }\n") fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}") fmt.Fprintf(f, "}\n")
} }
func generateUnvariadic(f *os.File, i int) { func generateUnvariadic(f *os.File, i int) {
@@ -144,7 +178,7 @@ func generateUnvariadic(f *os.File, i int) {
fmt.Fprintf(f, "v...)\n") fmt.Fprintf(f, "v...)\n")
fmt.Fprintf(f, " }\n") fmt.Fprintf(f, " }\n")
fmt.Fprintf(f, "}") fmt.Fprintf(f, "}\n")
} }
func generateNullary(f *os.File, i int) { func generateNullary(f *os.File, i int) {
@@ -347,6 +381,8 @@ func generatePipeHelpers(filename string, count int) error {
generateVariadic(f, 0) generateVariadic(f, 0)
// unvariadic // unvariadic
generateUnvariadic(f, 0) generateUnvariadic(f, 0)
// unsliced
generateUnsliced(f, 0)
for i := 1; i <= count; i++ { for i := 1; i <= count; i++ {
@@ -364,6 +400,8 @@ func generatePipeHelpers(filename string, count int) error {
generateVariadic(f, i) generateVariadic(f, i)
// unvariadic // unvariadic
generateUnvariadic(f, i) generateUnvariadic(f, i)
// unsliced
generateUnsliced(f, i)
} }
return nil return nil

View File

@@ -338,7 +338,7 @@ func generateUntupled(f *os.File, i int) {
func generateTupled(f *os.File, i int) { func generateTupled(f *os.File, i int) {
// Create the optionize version // Create the optionize version
fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters returning into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i) fmt.Fprintf(f, "\n// Tupled%d converts a function with %d parameters into a function taking a Tuple%d\n// The inverse function is [Untupled%d]\n", i, i, i, i)
fmt.Fprintf(f, "func Tupled%d[F ~func(", i) fmt.Fprintf(f, "func Tupled%d[F ~func(", i)
for j := 0; j < i; j++ { for j := 0; j < i; j++ {
if j > 0 { if j > 0 {

View File

@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
return R.TraverseArray[Reader[B], Reader[[]B], []A](f) return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) Reader[B]) func([]A) Reader[[]B] {
return R.TraverseArrayWithIndex[Reader[B], Reader[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] { func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
return R.SequenceArray[Reader[A], Reader[[]A]](ma) return R.SequenceArray[Reader[A], Reader[[]A]](ma)

View File

@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderEither[B]) func([]A) ReaderEither[[
return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f) return RE.TraverseArray[ReaderEither[B], ReaderEither[[]B], []A](f)
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderEither[B]) func([]A) ReaderEither[[]B] {
return RE.TraverseArrayWithIndex[ReaderEither[B], ReaderEither[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] { func SequenceArray[A any](ma []ReaderEither[A]) ReaderEither[[]A] {
return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma) return RE.SequenceArray[ReaderEither[A], ReaderEither[[]A]](ma)

View File

@@ -25,6 +25,11 @@ func TraverseArray[A, B any](f func(A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f) return R.TraverseArray[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIO[B]) func([]A) ReaderIO[[]B] {
return R.TraverseArrayWithIndex[ReaderIO[B], ReaderIO[[]B], IO.IO[B], IO.IO[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] { func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma) return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)

View File

@@ -18,6 +18,8 @@ package readerio
import ( import (
"context" "context"
IO "github.com/IBM/fp-go/io"
L "github.com/IBM/fp-go/lazy"
R "github.com/IBM/fp-go/readerio/generic" R "github.com/IBM/fp-go/readerio/generic"
) )
@@ -37,6 +39,22 @@ func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
return R.Chain[ReaderIO[A]](f) return R.Chain[ReaderIO[A]](f)
} }
func MonadChainIOK[A, B any](fa ReaderIO[A], f func(A) IO.IO[B]) ReaderIO[B] {
return R.MonadChainIOK[ReaderIO[A], ReaderIO[B]](fa, f)
}
func ChainIOK[A, B any](f func(A) IO.IO[B]) func(ReaderIO[A]) ReaderIO[B] {
return R.ChainIOK[ReaderIO[A], ReaderIO[B]](f)
}
func MonadChainFirstIOK[A, B any](fa ReaderIO[A], f func(A) IO.IO[B]) ReaderIO[A] {
return R.MonadChainFirstIOK[ReaderIO[A], ReaderIO[B]](fa, f)
}
func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(ReaderIO[A]) ReaderIO[A] {
return R.ChainFirstIOK[ReaderIO[A], ReaderIO[B]](f)
}
func Of[A any](a A) ReaderIO[A] { func Of[A any](a A) ReaderIO[A] {
return R.Of[ReaderIO[A]](a) return R.Of[ReaderIO[A]](a)
} }
@@ -54,6 +72,18 @@ func Ask() ReaderIO[context.Context] {
} }
// Defer creates an IO by creating a brand new IO via a generator function, each time // Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] { func Defer[A any](gen L.Lazy[ReaderIO[A]]) ReaderIO[A] {
return R.Defer[ReaderIO[A]](gen) return R.Defer[ReaderIO[A]](gen)
} }
// Memoize computes the value of the provided [ReaderIO] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[A any](rdr ReaderIO[A]) ReaderIO[A] {
return R.Memoize[ReaderIO[A]](rdr)
}
// Flatten converts a nested [ReaderIO] into a [ReaderIO]
func Flatten[A any](mma ReaderIO[ReaderIO[A]]) ReaderIO[A] {
return R.Flatten[ReaderIO[A]](mma)
}

View File

@@ -25,25 +25,31 @@ import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
"github.com/IBM/fp-go/internal/file" "github.com/IBM/fp-go/internal/file"
IOE "github.com/IBM/fp-go/ioeither" IOE "github.com/IBM/fp-go/ioeither"
IOEF "github.com/IBM/fp-go/ioeither/file"
) )
var ( var (
openIOE = IOE.Eitherize1(os.Open)
// Open opens a file for reading within the given context // Open opens a file for reading within the given context
Open = F.Flow3( Open = F.Flow3(
openIOE, IOEF.Open,
RIOE.FromIOEither[*os.File], RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File], RIOE.WithContext[*os.File],
) )
// Remove removes a file by name
Remove = F.Flow2(
IOEF.Remove,
RIOE.FromIOEither[string],
)
) )
// Close closes an object // Close closes an object
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] { func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
return RIOE.FromIOEither(func() ET.Either[error, any] { return F.Pipe2(
return ET.TryCatchError(func() (any, error) { c,
return c, c.Close() IOEF.Close[C],
}) RIOE.FromIOEither[any],
}) )
} }
// ReadFile reads a file in the scope of a context // ReadFile reads a file in the scope of a context

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 file
import (
"os"
RIOE "github.com/IBM/fp-go/context/readerioeither"
F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io"
IOF "github.com/IBM/fp-go/io/file"
IOEF "github.com/IBM/fp-go/ioeither/file"
)
var (
// onCreateTempFile creates a temp file with sensible defaults
onCreateTempFile = CreateTemp("", "*")
// destroy handler
onReleaseTempFile = F.Flow4(
IOF.Close[*os.File],
IO.Map((*os.File).Name),
RIOE.FromIO[string],
RIOE.Chain(Remove),
)
)
// CreateTemp created a temp file with proper parametrization
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
return F.Pipe2(
IOEF.CreateTemp(dir, pattern),
RIOE.FromIOEither[*os.File],
RIOE.WithContext[*os.File],
)
}
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
}

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package file
import (
"context"
"os"
"testing"
RIOE "github.com/IBM/fp-go/context/readerioeither"
E "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function"
"github.com/stretchr/testify/assert"
)
func TestWithTempFile(t *testing.T) {
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}
func TestWithTempFileOnClosedFile(t *testing.T) {
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
return F.Pipe2(
f,
onWriteAll[*os.File]([]byte("Carsten")),
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
)
})
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
}

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 file
import (
"context"
"io"
RIOE "github.com/IBM/fp-go/context/readerioeither"
F "github.com/IBM/fp-go/function"
)
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
return func(w W) RIOE.ReaderIOEither[[]byte] {
return F.Pipe1(
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
return func() ([]byte, error) {
_, err := w.Write(data)
return data, err
}
}),
RIOE.WithContext[[]byte],
)
}
}
// WriteAll uses a generator function to create a stream, writes data to it and closes it
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
onWrite := onWriteAll[W](data)
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
return RIOE.WithResource[[]byte](
onCreate,
Close[W])(
onWrite,
)
}
}
// Write uses a generator function to create a stream, writes data to it and closes it
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
return RIOE.WithResource[R](
acquire,
Close[W])
}

View File

@@ -2,7 +2,7 @@ package readerioeither
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101 // 2023-09-12 13:44:14.1022311 +0200 CEST m=+0.017763401
import ( import (
"context" "context"

View File

@@ -2,7 +2,7 @@ package generic
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:58:56.457404 +0200 CEST m=+0.024265101 // 2023-09-12 13:44:14.1036885 +0200 CEST m=+0.019220801
import ( import (
"context" "context"

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 generic
import (
"context"
ET "github.com/IBM/fp-go/either"
M "github.com/IBM/fp-go/monoid"
)
func ApplicativeMonoid[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadAp[GRA, GRA, GRFA],
m,
)
}
func ApplicativeMonoidSeq[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadApSeq[GRA, GRA, GRFA],
m,
)
}
func ApplicativeMonoidPar[GRA ~func(context.Context) GIOA, GRFA ~func(context.Context) GIOFA, GIOA ~func() ET.Either[error, A], GIOFA ~func() ET.Either[error, func(A) A], A any](
m M.Monoid[A],
) M.Monoid[GRA] {
return M.ApplicativeMonoid(
Of[GRA],
MonadMap[GRA, GRFA],
MonadApPar[GRA, GRA, GRFA],
m,
)
}

View File

@@ -100,6 +100,28 @@ func Map[
return RIE.Map[GRA, GRB](f) return RIE.Map[GRA, GRB](f)
} }
func MonadMapTo[
GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
A, B any](fa GRA, b B) GRB {
return RIE.MonadMapTo[GRA, GRB](fa, b)
}
func MapTo[
GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
A, B any](b B) func(GRA) GRB {
return RIE.MapTo[GRA, GRB](b)
}
func MonadChain[ func MonadChain[
GRA ~func(context.Context) GIOA, GRA ~func(context.Context) GIOA,
GRB ~func(context.Context) GIOB, GRB ~func(context.Context) GIOB,
@@ -458,6 +480,34 @@ func ChainIOK[
return RIE.ChainIOK[GRA, GRB](f) return RIE.ChainIOK[GRA, GRB](f)
} }
func MonadChainReaderIOK[
GRB ~func(context.Context) GIOB,
GRA ~func(context.Context) GIOA,
GRIO ~func(context.Context) GIO,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
GIO ~func() B,
A, B any](ma GRA, f func(A) GRIO) GRB {
return RIE.MonadChainReaderIOK[GRA, GRB](ma, f)
}
func ChainReaderIOK[
GRB ~func(context.Context) GIOB,
GRA ~func(context.Context) GIOA,
GRIO ~func(context.Context) GIO,
GIOA ~func() E.Either[error, A],
GIOB ~func() E.Either[error, B],
GIO ~func() B,
A, B any](f func(A) GRIO) func(ma GRA) GRB {
return RIE.ChainReaderIOK[GRA, GRB](f)
}
func MonadChainFirstIOK[ func MonadChainFirstIOK[
GRA ~func(context.Context) GIOA, GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A], GIOA ~func() E.Either[error, A],
@@ -543,3 +593,82 @@ func TryCatch[
A any](f func(context.Context) func() (A, error)) GRA { A any](f func(context.Context) func() (A, error)) GRA {
return RIE.TryCatch[GRA](f, ER.IdentityError) return RIE.TryCatch[GRA](f, ER.IdentityError)
} }
func MonadAlt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](first GEA, second LAZY) GEA {
return RIE.MonadAlt(first, second)
}
func Alt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](second LAZY) func(GEA) GEA {
return RIE.Alt(second)
}
// Memoize computes the value of the provided monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
A any](rdr GRA) GRA {
return RIE.Memoize[GRA](rdr)
}
func Flatten[
GGRA ~func(context.Context) GGIOA,
GGIOA ~func() E.Either[error, GRA],
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
A any](rdr GGRA) GRA {
return RIE.Flatten[GRA](rdr)
}
func MonadFromReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](a A, f func(A) GRIOA) GRIOEA {
return RIE.MonadFromReaderIO[GRIOEA](a, f)
}
func FromReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](f func(A) GRIOA) func(A) GRIOEA {
return RIE.FromReaderIO[GRIOEA](f)
}
func RightReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOA ~func(context.Context) GIOA,
GIOA ~func() A,
A any](ma GRIOA) GRIOEA {
return RIE.RightReaderIO[GRIOEA](ma)
}
func LeftReaderIO[
GRIOEA ~func(context.Context) GIOEA,
GIOEA ~func() E.Either[error, A],
GRIOE ~func(context.Context) GIOE,
GIOE ~func() error,
A any](ma GRIOE) GRIOEA {
return RIE.LeftReaderIO[GRIOEA](ma)
}
func MonadFlap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](fab GREAB, a A) GREB {
return RIE.MonadFlap[GREAB, GREB](fab, a)
}
func Flap[GREAB ~func(context.Context) GEAB, GREB ~func(context.Context) GEB, GEAB ~func() E.Either[error, func(A) B], GEB ~func() E.Either[error, B], B, A any](a A) func(GREAB) GREB {
return RIE.Flap[GREAB, GREB](a)
}

View File

@@ -0,0 +1,29 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
"context"
ET "github.com/IBM/fp-go/either"
S "github.com/IBM/fp-go/semigroup"
)
func AltSemigroup[GRA ~func(context.Context) GIOA, GIOA ~func() ET.Either[error, A], A any]() S.Semigroup[GRA] {
return S.AltSemigroup(
MonadAlt[func() GRA],
)
}

View File

@@ -62,6 +62,25 @@ func TraverseArray[
) )
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[
AS ~[]A,
GRBS ~func(context.Context) GIOBS,
GRB ~func(context.Context) GIOB,
GIOBS ~func() E.Either[error, BS],
GIOB ~func() E.Either[error, B],
BS ~[]B,
A, B any](f func(int, A) GRB) func(AS) GRBS {
return RA.TraverseWithIndex[AS](
Of[GRBS, GIOBS, BS],
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
f,
)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[ func SequenceArray[
AS ~[]A, AS ~[]A,
@@ -115,6 +134,26 @@ func TraverseRecord[K comparable,
) )
} }
// TraverseRecordWithIndex transforms a record
func TraverseRecordWithIndex[K comparable,
AS ~map[K]A,
GRBS ~func(context.Context) GIOBS,
GRB ~func(context.Context) GIOB,
GIOBS ~func() E.Either[error, BS],
GIOB ~func() E.Either[error, B],
BS ~map[K]B,
A, B any](f func(K, A) GRB) func(AS) GRBS {
return RR.TraverseWithIndex[AS](
Of[GRBS, GIOBS, BS],
Map[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GIOBS, func() E.Either[error, func(B) BS], BS, func(B) BS],
Ap[GRBS, func(context.Context) func() E.Either[error, func(B) BS], GRB],
f,
)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence // SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable, func SequenceRecord[K comparable,
AS ~map[K]A, AS ~map[K]A,

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 readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
L "github.com/IBM/fp-go/lazy"
M "github.com/IBM/fp-go/monoid"
)
// ApplicativeMonoid returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoid[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// ApplicativeMonoidSeq returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoidSeq[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoidSeq[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// ApplicativeMonoidPar returns a [Monoid] that concatenates [ReaderIOEither] instances via their applicative
func ApplicativeMonoidPar[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return G.ApplicativeMonoidPar[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
}
// AlternativeMonoid is the alternative [Monoid] for [ReaderIOEither]
func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
return M.AlternativeMonoid(
Of[A],
MonadMap[A, func(A) A],
MonadAp[A, A],
MonadAlt[A],
m,
)
}
// AltMonoid is the alternative [Monoid] for an [ReaderIOEither]
func AltMonoid[A any](zero L.Lazy[ReaderIOEither[A]]) M.Monoid[ReaderIOEither[A]] {
return M.AltMonoid(
zero,
MonadAlt[A],
)
}

View File

@@ -25,6 +25,7 @@ import (
ET "github.com/IBM/fp-go/either" ET "github.com/IBM/fp-go/either"
IO "github.com/IBM/fp-go/io" IO "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither" IOE "github.com/IBM/fp-go/ioeither"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
@@ -60,6 +61,14 @@ func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f) return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
} }
func MonadMapTo[A, B any](fa ReaderIOEither[A], b B) ReaderIOEither[B] {
return G.MonadMapTo[ReaderIOEither[A], ReaderIOEither[B]](fa, b)
}
func MapTo[A, B any](b B) func(ReaderIOEither[A]) ReaderIOEither[B] {
return G.MapTo[ReaderIOEither[A], ReaderIOEither[B]](b)
}
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] { func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
return G.MonadChain(ma, f) return G.MonadChain(ma, f)
} }
@@ -146,11 +155,23 @@ func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
return G.FromIO[ReaderIOEither[A]](t) return G.FromIO[ReaderIOEither[A]](t)
} }
func FromLazy[A any](t L.Lazy[A]) ReaderIOEither[A] {
return G.FromIO[ReaderIOEither[A]](t)
}
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled // Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
func Never[A any]() ReaderIOEither[A] { func Never[A any]() ReaderIOEither[A] {
return G.Never[ReaderIOEither[A]]() return G.Never[ReaderIOEither[A]]()
} }
func MonadChainReaderIOK[A, B any](ma ReaderIOEither[A], f func(A) RIO.ReaderIO[B]) ReaderIOEither[B] {
return G.MonadChainReaderIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f)
}
func ChainReaderIOK[A, B any](f func(A) RIO.ReaderIO[B]) func(ma ReaderIOEither[A]) ReaderIOEither[B] {
return G.ChainReaderIOK[ReaderIOEither[B], ReaderIOEither[A]](f)
}
func MonadChainIOK[A, B any](ma ReaderIOEither[A], f func(A) IO.IO[B]) ReaderIOEither[B] { func MonadChainIOK[A, B any](ma ReaderIOEither[A], f func(A) IO.IO[B]) ReaderIOEither[B] {
return G.MonadChainIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f) return G.MonadChainIOK[ReaderIOEither[B], ReaderIOEither[A]](ma, f)
} }
@@ -182,7 +203,7 @@ func Timer(delay time.Duration) ReaderIOEither[time.Time] {
} }
// Defer creates an IO by creating a brand new IO via a generator function, each time // Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] { func Defer[A any](gen L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.Defer[ReaderIOEither[A]](gen) return G.Defer[ReaderIOEither[A]](gen)
} }
@@ -190,3 +211,50 @@ func Defer[A any](gen func() ReaderIOEither[A]) ReaderIOEither[A] {
func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] { func TryCatch[A any](f func(context.Context) func() (A, error)) ReaderIOEither[A] {
return G.TryCatch[ReaderIOEither[A]](f) return G.TryCatch[ReaderIOEither[A]](f)
} }
// MonadAlt identifies an associative operation on a type constructor
func MonadAlt[A any](first ReaderIOEither[A], second L.Lazy[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.MonadAlt(first, second)
}
// Alt identifies an associative operation on a type constructor
func Alt[A any](second L.Lazy[ReaderIOEither[A]]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.Alt(second)
}
// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
return G.Memoize[ReaderIOEither[A]](rdr)
}
// Flatten converts a nested [ReaderIOEither] into a [ReaderIOEither]
func Flatten[
A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
return G.Flatten[ReaderIOEither[ReaderIOEither[A]]](rdr)
}
func MonadFromReaderIO[A any](a A, f func(A) RIO.ReaderIO[A]) ReaderIOEither[A] {
return G.MonadFromReaderIO[ReaderIOEither[A]](a, f)
}
func FromReaderIO[A any](f func(A) RIO.ReaderIO[A]) func(A) ReaderIOEither[A] {
return G.FromReaderIO[ReaderIOEither[A]](f)
}
func RightReaderIO[A any](ma RIO.ReaderIO[A]) ReaderIOEither[A] {
return G.RightReaderIO[ReaderIOEither[A]](ma)
}
func LeftReaderIO[A any](ma RIO.ReaderIO[error]) ReaderIOEither[A] {
return G.LeftReaderIO[ReaderIOEither[A]](ma)
}
func MonadFlap[B, A any](fab ReaderIOEither[func(A) B], a A) ReaderIOEither[B] {
return G.MonadFlap[ReaderIOEither[func(A) B], ReaderIOEither[B]](fab, a)
}
func Flap[B, A any](a A) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
return G.Flap[ReaderIOEither[func(A) B], ReaderIOEither[B]](a)
}

View File

@@ -162,3 +162,125 @@ func TestRegularApply(t *testing.T) {
res := applied(context.Background())() res := applied(context.Background())()
assert.Equal(t, E.Of[error]("CARSTEN"), res) assert.Equal(t, E.Of[error]("CARSTEN"), res)
} }
func TestWithResourceNoErrors(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 1, countBody)
assert.Equal(t, 1, countRelease)
assert.Equal(t, E.Of[error](1), res)
}
func TestWithResourceErrorInBody(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
err := fmt.Errorf("error in body")
body := func(int) ReaderIOEither[int] {
return Left[int](err)
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 0, countBody)
assert.Equal(t, 1, countRelease)
assert.Equal(t, E.Left[int](err), res)
}
func TestWithResourceErrorInAcquire(t *testing.T) {
var countAcquire, countBody, countRelease int
err := fmt.Errorf("error in acquire")
acquire := Left[int](err)
release := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countRelease++
return countRelease
})
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 0, countAcquire)
assert.Equal(t, 0, countBody)
assert.Equal(t, 0, countRelease)
assert.Equal(t, E.Left[int](err), res)
}
func TestWithResourceErrorInRelease(t *testing.T) {
var countAcquire, countBody, countRelease int
acquire := FromLazy(func() int {
countAcquire++
return countAcquire
})
err := fmt.Errorf("error in release")
release := func(int) ReaderIOEither[int] {
return Left[int](err)
}
body := func(int) ReaderIOEither[int] {
return FromLazy(func() int {
countBody++
return countBody
})
}
resRIOE := WithResource[int](acquire, release)(body)
res := resRIOE(context.Background())()
assert.Equal(t, 1, countAcquire)
assert.Equal(t, 1, countBody)
assert.Equal(t, 0, countRelease)
assert.Equal(t, E.Left[int](err), res)
}

View File

@@ -0,0 +1,26 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package readerioeither
import (
G "github.com/IBM/fp-go/context/readerioeither/generic"
S "github.com/IBM/fp-go/semigroup"
)
// AltSemigroup is a [Semigroup] that tries the first item and then the second one using an alternative
func AltSemigroup[A any]() S.Semigroup[ReaderIOEither[A]] {
return G.AltSemigroup[ReaderIOEither[A]]()
}

View File

@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) ReaderIOEither[B]) func([]A) ReaderIOEith
return G.TraverseArray[[]A, ReaderIOEither[[]B]](f) return G.TraverseArray[[]A, ReaderIOEither[[]B]](f)
} }
// TraverseArrayWithIndex uses transforms an array [[]A] into [[]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[[]B]]
func TraverseArrayWithIndex[A, B any](f func(int, A) ReaderIOEither[B]) func([]A) ReaderIOEither[[]B] {
return G.TraverseArrayWithIndex[[]A, ReaderIOEither[[]B]](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] { func SequenceArray[A any](ma []ReaderIOEither[A]) ReaderIOEither[[]A] {
return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma) return G.SequenceArray[[]A, []ReaderIOEither[A], ReaderIOEither[[]A]](ma)
@@ -34,6 +39,11 @@ func TraverseRecord[K comparable, A, B any](f func(A) ReaderIOEither[B]) func(ma
return G.TraverseRecord[K, map[K]A, ReaderIOEither[map[K]B]](f) return G.TraverseRecord[K, map[K]A, ReaderIOEither[map[K]B]](f)
} }
// TraverseRecordWithIndex uses transforms a record [map[K]A] into [map[K]ReaderIOEither[B]] and then resolves that into a [ReaderIOEither[map[K]B]]
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) ReaderIOEither[B]) func(map[K]A) ReaderIOEither[map[K]B] {
return G.TraverseRecordWithIndex[K, map[K]A, ReaderIOEither[map[K]B]](f)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence // SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] { func SequenceRecord[K comparable, A any](ma map[K]ReaderIOEither[A]) ReaderIOEither[map[K]A] {
return G.SequenceRecord[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma) return G.SequenceRecord[K, map[K]A, map[K]ReaderIOEither[A], ReaderIOEither[map[K]A]](ma)

2
coverage.bat Normal file
View File

@@ -0,0 +1,2 @@
@echo off
go tool cover -html=build/cover.out -o build/cover.html

View File

@@ -24,6 +24,7 @@ func ApplySemigroup[E, A any](s S.Semigroup[A]) S.Semigroup[Either[E, A]] {
return S.ApplySemigroup(MonadMap[E, A, func(A) A], MonadAp[A, E, A], s) return S.ApplySemigroup(MonadMap[E, A, func(A) A], MonadAp[A, E, A], s)
} }
// ApplicativeMonoid returns a [Monoid] that concatenates [Either] instances via their applicative
func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] { func ApplicativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m) return M.ApplicativeMonoid(Of[E, A], MonadMap[E, A, func(A) A], MonadAp[A, E, A], m)
} }

View File

@@ -20,7 +20,7 @@ import (
RA "github.com/IBM/fp-go/internal/array" RA "github.com/IBM/fp-go/internal/array"
) )
// TraverseArray transforms an array // TraverseArrayG transforms an array
func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] { func TraverseArrayG[GA ~[]A, GB ~[]B, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
return RA.Traverse[GA]( return RA.Traverse[GA](
Of[E, GB], Of[E, GB],
@@ -36,6 +36,22 @@ func TraverseArray[E, A, B any](f func(A) Either[E, B]) func([]A) Either[E, []B]
return TraverseArrayG[[]A, []B](f) return TraverseArrayG[[]A, []B](f)
} }
// TraverseArrayWithIndexG transforms an array
func TraverseArrayWithIndexG[GA ~[]A, GB ~[]B, E, A, B any](f func(int, A) Either[E, B]) func(GA) Either[E, GB] {
return RA.TraverseWithIndex[GA](
Of[E, GB],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[E, A, B any](f func(int, A) Either[E, B]) func([]A) Either[E, []B] {
return TraverseArrayWithIndexG[[]A, []B](f)
}
func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA] { func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA] {
return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma) return TraverseArrayG[GOA, GA](F.Identity[Either[E, A]])(ma)
} }
@@ -44,3 +60,15 @@ func SequenceArrayG[GA ~[]A, GOA ~[]Either[E, A], E, A any](ma GOA) Either[E, GA
func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] { func SequenceArray[E, A any](ma []Either[E, A]) Either[E, []A] {
return SequenceArrayG[[]A](ma) return SequenceArrayG[[]A](ma)
} }
// CompactArrayG discards the none values and keeps the some values
func CompactArrayG[A1 ~[]Either[E, A], A2 ~[]A, E, A any](fa A1) A2 {
return RA.Reduce(fa, func(out A2, value Either[E, A]) A2 {
return MonadFold(value, F.Constant1[E](out), F.Bind1st(RA.Append[A2, A], out))
}, make(A2, len(fa)))
}
// CompactArray discards the none values and keeps the some values
func CompactArray[E, A any](fa []Either[E, A]) []A {
return CompactArrayG[[]Either[E, A], []A](fa)
}

View File

@@ -22,6 +22,8 @@ package either
import ( import (
E "github.com/IBM/fp-go/errors" E "github.com/IBM/fp-go/errors"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
FC "github.com/IBM/fp-go/internal/functor"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
@@ -91,12 +93,12 @@ func MonadChainTo[E, A, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
return mb return mb
} }
func MonadChainOptionK[E, A, B any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] { func MonadChainOptionK[A, B, E any](onNone func() E, ma Either[E, A], f func(A) O.Option[B]) Either[E, B] {
return MonadChain(ma, F.Flow2(f, FromOption[E, B](onNone))) return MonadChain(ma, F.Flow2(f, FromOption[B](onNone)))
} }
func ChainOptionK[E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] { func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
from := FromOption[E, B](onNone) from := FromOption[B](onNone)
return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] { return func(f func(A) O.Option[B]) func(Either[E, A]) Either[E, B] {
return Chain(F.Flow2(f, from)) return Chain(F.Flow2(f, from))
} }
@@ -142,7 +144,7 @@ func Sequence3[E, T1, T2, T3, R any](f func(T1, T2, T3) Either[E, R]) func(Eithe
} }
} }
func FromOption[E, A any](onNone func() E) func(O.Option[A]) Either[E, A] { func FromOption[A, E any](onNone func() E) func(O.Option[A]) Either[E, A] {
return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A]) return O.Fold(F.Nullary2(onNone, Left[A, E]), Right[E, A])
} }
@@ -197,11 +199,11 @@ func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B {
) )
} }
func AltW[E, E1, A any](that func() Either[E1, A]) func(Either[E, A]) Either[E1, A] { func AltW[E, E1, A any](that L.Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A] {
return Fold(F.Ignore1of1[E](that), Right[E1, A]) return Fold(F.Ignore1of1[E](that), Right[E1, A])
} }
func Alt[E, A any](that func() Either[E, A]) func(Either[E, A]) Either[E, A] { func Alt[E, A any](that L.Lazy[Either[E, A]]) func(Either[E, A]) Either[E, A] {
return AltW[E](that) return AltW[E](that)
} }
@@ -209,7 +211,7 @@ func OrElse[E, A any](onLeft func(e E) Either[E, A]) func(Either[E, A]) Either[E
return Fold(onLeft, Of[E, A]) return Fold(onLeft, Of[E, A])
} }
func ToType[E, A any](onError func(any) E) func(any) Either[E, A] { func ToType[A, E any](onError func(any) E) func(any) Either[E, A] {
return func(value any) Either[E, A] { return func(value any) Either[E, A] {
return F.Pipe2( return F.Pipe2(
value, value,
@@ -245,3 +247,15 @@ func MonadSequence3[E, T1, T2, T3, R any](e1 Either[E, T1], e2 Either[E, T2], e3
func Swap[E, A any](val Either[E, A]) Either[A, E] { func Swap[E, A any](val Either[E, A]) Either[A, E] {
return MonadFold(val, Right[A, E], Left[E, A]) return MonadFold(val, Right[A, E], Left[E, A])
} }
func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
return FC.MonadFlap(MonadMap[E, func(A) B, B], fab, a)
}
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
return F.Bind2nd(MonadFlap[E, B, A], a)
}
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
return MonadFold(fa, F.Ignore1of1[E](that), Of[E, A])
}

View File

@@ -100,7 +100,7 @@ func TestChainFirst(t *testing.T) {
} }
func TestChainOptionK(t *testing.T) { func TestChainOptionK(t *testing.T) {
f := ChainOptionK[string, int, int](F.Constant("a"))(func(n int) O.Option[int] { f := ChainOptionK[int, int](F.Constant("a"))(func(n int) O.Option[int] {
if n > 0 { if n > 0 {
return O.Some(n) return O.Some(n)
} }
@@ -112,6 +112,6 @@ func TestChainOptionK(t *testing.T) {
} }
func TestFromOption(t *testing.T) { func TestFromOption(t *testing.T) {
assert.Equal(t, Left[int]("none"), FromOption[string, int](F.Constant("none"))(O.None[int]())) assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
assert.Equal(t, Right[string](1), FromOption[string, int](F.Constant("none"))(O.Some(1))) assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
} }

View File

@@ -27,7 +27,7 @@ import (
var ( var (
// Command executes a command // Command executes a command
// use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input // use this version if the command does not produce any side effect, i.e. if the output is uniquely determined by by the input
// typically you'd rather use the IOEither version of the command // typically you'd rather use the [IOEither] version of the command
Command = F.Curry3(command) Command = F.Curry3(command)
) )

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:58:57.9925506 +0200 CEST m=+0.033401101 // 2023-09-12 13:44:15.6356542 +0200 CEST m=+0.009418901
package either package either

40
either/monoid.go Normal file
View File

@@ -0,0 +1,40 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package either
import (
L "github.com/IBM/fp-go/lazy"
M "github.com/IBM/fp-go/monoid"
)
// AlternativeMonoid is the alternative [Monoid] for an [Either]
func AlternativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
return M.AlternativeMonoid(
Of[E, A],
MonadMap[E, A, func(A) A],
MonadAp[A, E, A],
MonadAlt[E, A],
m,
)
}
// AltMonoid is the alternative [Monoid] for an [Either]
func AltMonoid[E, A any](zero L.Lazy[Either[E, A]]) M.Monoid[Either[E, A]] {
return M.AltMonoid(
zero,
MonadAlt[E, A],
)
}

View File

@@ -20,7 +20,7 @@ import (
RR "github.com/IBM/fp-go/internal/record" RR "github.com/IBM/fp-go/internal/record"
) )
// TraverseRecord transforms a record of options into an option of a record // TraverseRecordG transforms a record of options into an option of a record
func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] { func TraverseRecordG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(A) Either[E, B]) func(GA) Either[E, GB] {
return RR.Traverse[GA]( return RR.Traverse[GA](
Of[E, GB], Of[E, GB],
@@ -35,6 +35,21 @@ func TraverseRecord[K comparable, E, A, B any](f func(A) Either[E, B]) func(map[
return TraverseRecordG[map[K]A, map[K]B](f) return TraverseRecordG[map[K]A, map[K]B](f)
} }
// TraverseRecordWithIndexG transforms a record of options into an option of a record
func TraverseRecordWithIndexG[GA ~map[K]A, GB ~map[K]B, K comparable, E, A, B any](f func(K, A) Either[E, B]) func(GA) Either[E, GB] {
return RR.TraverseWithIndex[GA](
Of[E, GB],
Map[E, GB, func(B) GB],
Ap[GB, E, B],
f,
)
}
// TraverseRecordWithIndex transforms a record of eithers into an either of a record
func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) Either[E, B]) func(map[K]A) Either[E, map[K]B] {
return TraverseRecordWithIndexG[map[K]A, map[K]B](f)
}
func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA] { func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A any](ma GOA) Either[E, GA] {
return TraverseRecordG[GOA, GA](F.Identity[Either[E, A]])(ma) return TraverseRecordG[GOA, GA](F.Identity[Either[E, A]])(ma)
} }
@@ -43,3 +58,24 @@ func SequenceRecordG[GA ~map[K]A, GOA ~map[K]Either[E, A], K comparable, E, A an
func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A] { func SequenceRecord[K comparable, E, A any](ma map[K]Either[E, A]) Either[E, map[K]A] {
return SequenceRecordG[map[K]A](ma) return SequenceRecordG[map[K]A](ma)
} }
func upsertAtReadWrite[M ~map[K]V, K comparable, V any](r M, k K, v V) M {
r[k] = v
return r
}
// CompactRecordG discards the noe values and keeps the some values
func CompactRecordG[M1 ~map[K]Either[E, A], M2 ~map[K]A, K comparable, E, A any](m M1) M2 {
out := make(M2)
onLeft := F.Constant1[E](out)
return RR.ReduceWithIndex(m, func(key K, _ M2, value Either[E, A]) M2 {
return MonadFold(value, onLeft, func(v A) M2 {
return upsertAtReadWrite(out, key, v)
})
}, out)
}
// CompactRecord discards all none values and keeps the somes
func CompactRecord[K comparable, E, A any](m map[K]Either[E, A]) map[K]A {
return CompactRecordG[map[K]Either[E, A], map[K]A](m)
}

37
either/record_test.go Normal file
View File

@@ -0,0 +1,37 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package either
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestCompactRecord(t *testing.T) {
// make the map
m := make(map[string]Either[string, int])
m["foo"] = Left[int]("error")
m["bar"] = Right[string](1)
// compact it
m1 := CompactRecord(m)
// check expected
exp := map[string]int{
"bar": 1,
}
assert.Equal(t, exp, m1)
}

View File

@@ -13,17 +13,15 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package file package either
import ( import (
"io" S "github.com/IBM/fp-go/semigroup"
IOE "github.com/IBM/fp-go/ioeither"
) )
// onClose closes a closeable resource // AltSemigroup is the alternative [Semigroup] for an [Either]
func onClose[R io.Closer](r R) IOE.IOEither[error, R] { func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]] {
return IOE.TryCatchError(func() (R, error) { return S.AltSemigroup(
return r, r.Close() MonadAlt[E, A],
}) )
} }

View File

@@ -27,13 +27,13 @@ HKTRB = HKT<Either[B]>
HKTA = HKT<A> HKTA = HKT<A>
HKTB = HKT<B> HKTB = HKT<B>
*/ */
func traverse[E, A, B, HKTA, HKTB, HKTRB any]( func traverse[E, A, B, HKTB, HKTRB any](
_of func(Either[E, B]) HKTRB, mof func(Either[E, B]) HKTRB,
_map func(HKTB, func(B) Either[E, B]) HKTRB, mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(Either[E, A], func(A) HKTB) HKTRB { ) func(Either[E, A], func(A) HKTB) HKTRB {
left := F.Flow2(Left[B, E], _of) left := F.Flow2(Left[B, E], mof)
right := F.Bind2nd(_map, Right[E, B]) right := mmap(Right[E, B])
return func(ta Either[E, A], f func(A) HKTB) HKTRB { return func(ta Either[E, A], f func(A) HKTB) HKTRB {
return MonadFold(ta, return MonadFold(ta,
@@ -43,27 +43,21 @@ func traverse[E, A, B, HKTA, HKTB, HKTRB any](
} }
} }
func Traverse[E, A, B, HKTA, HKTB, HKTRB any]( // Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
_of func(Either[E, B]) HKTRB, func Traverse[A, E, B, HKTB, HKTRB any](
_map func(HKTB, func(B) Either[E, B]) HKTRB, mof func(Either[E, B]) HKTRB,
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
) func(func(A) HKTB) func(Either[E, A]) HKTRB { ) func(func(A) HKTB) func(Either[E, A]) HKTRB {
delegate := traverse[E, A, B, HKTA](_of, _map) delegate := traverse[E, A, B](mof, mmap)
return func(f func(A) HKTB) func(Either[E, A]) HKTRB { return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
return F.Bind2nd(delegate, f) return F.Bind2nd(delegate, f)
} }
} }
/* // Sequence converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
*
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
HKTRA = HKT<Either[A]>
HKTA = HKT<A>
HKTB = HKT<B>
*/
func Sequence[E, A, HKTA, HKTRA any]( func Sequence[E, A, HKTA, HKTRA any](
_of func(Either[E, A]) HKTRA, mof func(Either[E, A]) HKTRA,
_map func(HKTA, func(A) Either[E, A]) HKTRA, mmap func(func(A) Either[E, A]) func(HKTA) HKTRA,
) func(Either[E, HKTA]) HKTRA { ) func(Either[E, HKTA]) HKTRA {
return Fold(F.Flow2(Left[A, E], _of), F.Bind2nd(_map, Right[E, A])) return Fold(F.Flow2(Left[A, E], mof), mmap(Right[E, A]))
} }

View File

@@ -30,9 +30,9 @@ func TestTraverse(t *testing.T) {
} }
return O.None[int]() return O.None[int]()
} }
trav := Traverse[string, int, int, O.Option[Either[string, int]]]( trav := Traverse[int](
O.Of[Either[string, int]], O.Of[Either[string, int]],
O.MonadMap[int, Either[string, int]], O.Map[int, Either[string, int]],
)(f) )(f)
assert.Equal(t, O.Of(Left[int]("a")), F.Pipe1(Left[int]("a"), trav)) assert.Equal(t, O.Of(Left[int]("a")), F.Pipe1(Left[int]("a"), trav))
@@ -44,7 +44,7 @@ func TestSequence(t *testing.T) {
seq := Sequence( seq := Sequence(
O.Of[Either[string, int]], O.Of[Either[string, int]],
O.MonadMap[int, Either[string, int]], O.Map[int, Either[string, int]],
) )
assert.Equal(t, O.Of(Right[string](1)), seq(Right[string](O.Of(1)))) assert.Equal(t, O.Of(Right[string](1)), seq(Right[string](O.Of(1))))

View File

@@ -20,11 +20,14 @@ import (
) )
type ( type (
// command output // CommandOutput represents the output of executing a command. The first field in the [Tuple2] is
// stdout, the second one is stderr. Use [StdOut] and [StdErr] to access these fields
CommandOutput = T.Tuple2[[]byte, []byte] CommandOutput = T.Tuple2[[]byte, []byte]
) )
var ( var (
// StdOut returns the field of a [CommandOutput] representing `stdout`
StdOut = T.First[[]byte, []byte] StdOut = T.First[[]byte, []byte]
// StdErr returns the field of a [CommandOutput] representing `stderr`
StdErr = T.Second[[]byte, []byte] StdErr = T.Second[[]byte, []byte]
) )

View File

@@ -15,9 +15,11 @@
package file package file
import "os" import "path/filepath"
// GetName is the getter for the `Name` property of [os.File] // Join appends a filename to a root path
func GetName(f *os.File) string { func Join(name string) func(root string) string {
return f.Name() return func(root string) string {
return filepath.Join(root, name)
}
} }

View File

@@ -26,6 +26,7 @@ func Bind2nd[T1, T2, R any](f func(T1, T2) R, t2 T2) func(T1) R {
} }
} }
// SK function (SKI combinator calculus).
func SK[T1, T2 any](_ T1, t2 T2) T2 { func SK[T1, T2 any](_ T1, t2 T2) T2 {
return t2 return t2
} }

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:01.9404821 +0200 CEST m=+0.161366801 // 2023-09-12 13:44:23.4226437 +0200 CEST m=+0.011841001
package function package function

View File

@@ -19,12 +19,12 @@ import (
G "github.com/IBM/fp-go/function/generic" G "github.com/IBM/fp-go/function/generic"
) )
// Cache converts a unary function into a unary function that caches the value depending on the parameter // Memoize converts a unary function into a unary function that caches the value depending on the parameter
func Cache[K comparable, T any](f func(K) T) func(K) T { func Memoize[K comparable, T any](f func(K) T) func(K) T {
return G.Cache(f) return G.Memoize(f)
} }
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter // ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
func ContramapCache[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T { func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
return G.ContramapCache[func(A) T](kf) return G.ContramapMemoize[func(A) T](kf)
} }

View File

@@ -29,7 +29,7 @@ func TestCache(t *testing.T) {
return n return n
} }
cached := Cache(withSideEffect) cached := Memoize(withSideEffect)
assert.Equal(t, 0, count) assert.Equal(t, 0, count)

View File

@@ -62,6 +62,7 @@ func First[T1, T2 any](t1 T1, _ T2) T1 {
} }
// Second returns the second out of two input values // Second returns the second out of two input values
// Identical to [SK]
func Second[T1, T2 any](_ T1, t2 T2) T2 { func Second[T1, T2 any](_ T1, t2 T2) T2 {
return t2 return t2
} }

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:58:59.8663985 +0200 CEST m=+0.103744101 // 2023-09-12 13:44:17.0002767 +0200 CEST m=+0.008233101
package function package function
@@ -24,6 +24,13 @@ func Unvariadic0[V, R any](f func(...V) R) func([]V) R {
} }
} }
// Unsliced0 converts a function taking a slice parameter into a function with 0 parameters
func Unsliced0[F ~func([]T) R, T, R any](f F) func() R {
return func() R {
return f([]T{})
}
}
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function // Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 { func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
@@ -76,6 +83,13 @@ func Unvariadic1[T1, V, R any](f func(T1, ...V) R) func(T1, []V) R {
} }
} }
// Unsliced1 converts a function taking a slice parameter into a function with 1 parameters
func Unsliced1[F ~func([]T) R, T, R any](f F) func(T) R {
return func(t1 T) R {
return f([]T{t1})
}
}
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function // Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 { func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
@@ -131,6 +145,13 @@ func Unvariadic2[T1, T2, V, R any](f func(T1, T2, ...V) R) func(T1, T2, []V) R {
} }
} }
// Unsliced2 converts a function taking a slice parameter into a function with 2 parameters
func Unsliced2[F ~func([]T) R, T, R any](f F) func(T, T) R {
return func(t1, t2 T) R {
return f([]T{t1, t2})
}
}
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function // Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 { func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
@@ -189,6 +210,13 @@ func Unvariadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, ...V) R) func(T1, T2,
} }
} }
// Unsliced3 converts a function taking a slice parameter into a function with 3 parameters
func Unsliced3[F ~func([]T) R, T, R any](f F) func(T, T, T) R {
return func(t1, t2, t3 T) R {
return f([]T{t1, t2, t3})
}
}
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function // Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 { func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
@@ -250,6 +278,13 @@ func Unvariadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, ...V) R) func(
} }
} }
// Unsliced4 converts a function taking a slice parameter into a function with 4 parameters
func Unsliced4[F ~func([]T) R, T, R any](f F) func(T, T, T, T) R {
return func(t1, t2, t3, t4 T) R {
return f([]T{t1, t2, t3, t4})
}
}
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function // Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 { func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
@@ -314,6 +349,13 @@ func Unvariadic5[T1, T2, T3, T4, T5, V, R any](f func(T1, T2, T3, T4, T5, ...V)
} }
} }
// Unsliced5 converts a function taking a slice parameter into a function with 5 parameters
func Unsliced5[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5 T) R {
return f([]T{t1, t2, t3, t4, t5})
}
}
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function // Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 { func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
@@ -381,6 +423,13 @@ func Unvariadic6[T1, T2, T3, T4, T5, T6, V, R any](f func(T1, T2, T3, T4, T5, T6
} }
} }
// Unsliced6 converts a function taking a slice parameter into a function with 6 parameters
func Unsliced6[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6 T) R {
return f([]T{t1, t2, t3, t4, t5, t6})
}
}
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function // Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 { func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
@@ -451,6 +500,13 @@ func Unvariadic7[T1, T2, T3, T4, T5, T6, T7, V, R any](f func(T1, T2, T3, T4, T5
} }
} }
// Unsliced7 converts a function taking a slice parameter into a function with 7 parameters
func Unsliced7[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7})
}
}
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function // Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 { func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
@@ -524,6 +580,13 @@ func Unvariadic8[T1, T2, T3, T4, T5, T6, T7, T8, V, R any](f func(T1, T2, T3, T4
} }
} }
// Unsliced8 converts a function taking a slice parameter into a function with 8 parameters
func Unsliced8[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8})
}
}
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function // Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 { func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
@@ -600,6 +663,13 @@ func Unvariadic9[T1, T2, T3, T4, T5, T6, T7, T8, T9, V, R any](f func(T1, T2, T3
} }
} }
// Unsliced9 converts a function taking a slice parameter into a function with 9 parameters
func Unsliced9[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9})
}
}
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function // Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 { func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
@@ -679,6 +749,13 @@ func Unvariadic10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, V, R any](f func(T1,
} }
} }
// Unsliced10 converts a function taking a slice parameter into a function with 10 parameters
func Unsliced10[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10})
}
}
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function // Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 { func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
@@ -761,6 +838,13 @@ func Unvariadic11[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, V, R any](f func
} }
} }
// Unsliced11 converts a function taking a slice parameter into a function with 11 parameters
func Unsliced11[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11})
}
}
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function // Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 { func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
@@ -846,6 +930,13 @@ func Unvariadic12[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, V, R any](f
} }
} }
// Unsliced12 converts a function taking a slice parameter into a function with 12 parameters
func Unsliced12[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12})
}
}
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function // Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 { func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
@@ -934,6 +1025,13 @@ func Unvariadic13[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, V, R a
} }
} }
// Unsliced13 converts a function taking a slice parameter into a function with 13 parameters
func Unsliced13[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13})
}
}
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function // Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 { func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
@@ -1025,6 +1123,13 @@ func Unvariadic14[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, V
} }
} }
// Unsliced14 converts a function taking a slice parameter into a function with 14 parameters
func Unsliced14[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14})
}
}
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function // Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 { func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
@@ -1119,6 +1224,13 @@ func Unvariadic15[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
} }
} }
// Unsliced15 converts a function taking a slice parameter into a function with 15 parameters
func Unsliced15[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15})
}
}
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function // Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 { func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
@@ -1216,6 +1328,13 @@ func Unvariadic16[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
} }
} }
// Unsliced16 converts a function taking a slice parameter into a function with 16 parameters
func Unsliced16[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16})
}
}
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function // Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 { func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
@@ -1316,6 +1435,13 @@ func Unvariadic17[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
} }
} }
// Unsliced17 converts a function taking a slice parameter into a function with 17 parameters
func Unsliced17[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17})
}
}
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function // Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 { func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
@@ -1419,6 +1545,13 @@ func Unvariadic18[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
} }
} }
// Unsliced18 converts a function taking a slice parameter into a function with 18 parameters
func Unsliced18[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18})
}
}
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function // Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 { func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
@@ -1525,6 +1658,13 @@ func Unvariadic19[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
} }
} }
// Unsliced19 converts a function taking a slice parameter into a function with 19 parameters
func Unsliced19[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19})
}
}
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function // Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
// The final return value is the result of the last function application // The final return value is the result of the last function application
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 { func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
@@ -1633,3 +1773,10 @@ func Unvariadic20[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T
return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, v...) return f(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20, v...)
} }
} }
// Unsliced20 converts a function taking a slice parameter into a function with 20 parameters
func Unsliced20[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T, T) R {
return func(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20 T) R {
return f([]T{t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20})
}
}

View File

@@ -21,13 +21,13 @@ import (
L "github.com/IBM/fp-go/internal/lazy" L "github.com/IBM/fp-go/internal/lazy"
) )
// Cache converts a unary function into a unary function that caches the value depending on the parameter // Memoize converts a unary function into a unary function that caches the value depending on the parameter
func Cache[F ~func(K) T, K comparable, T any](f F) F { func Memoize[F ~func(K) T, K comparable, T any](f F) F {
return ContramapCache[F](func(k K) K { return k })(f) return ContramapMemoize[F](func(k K) K { return k })(f)
} }
// ContramapCache converts a unary function into a unary function that caches the value depending on the parameter // ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
func ContramapCache[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F { func ContramapMemoize[F ~func(A) T, KF func(A) K, A any, K comparable, T any](kf KF) func(F) F {
return CacheCallback[F](kf, getOrCreate[K, T]()) return CacheCallback[F](kf, getOrCreate[K, T]())
} }

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 function
import (
"strings"
"testing"
"github.com/stretchr/testify/assert"
)
func fromLibrary(data ...string) string {
return strings.Join(data, "-")
}
func TestUnvariadic(t *testing.T) {
res := Pipe1(
[]string{"A", "B"},
Unvariadic0(fromLibrary),
)
assert.Equal(t, "A-B", res)
}
func TestVariadicArity(t *testing.T) {
f := Unsliced2(Unvariadic0(fromLibrary))
res := f("A", "B")
assert.Equal(t, "A-B", res)
}

View File

@@ -57,7 +57,7 @@ var (
GetHeader, GetHeader,
R.Lookup[H.Header](HeaderContentType), R.Lookup[H.Header](HeaderContentType),
O.Chain(A.First[string]), O.Chain(A.First[string]),
E.FromOption[error, string](errors.OnNone("unable to access the [%s] header", HeaderContentType)), E.FromOption[string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
E.ChainFirst(validateJsonContentTypeString), E.ChainFirst(validateJsonContentTypeString),
))) )))
) )

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:06.2987136 +0200 CEST m=+0.049156901 // 2023-09-12 13:44:24.9409324 +0200 CEST m=+0.008573601
package identity package identity

View File

@@ -18,6 +18,7 @@ package generic
import ( import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
C "github.com/IBM/fp-go/internal/chain" C "github.com/IBM/fp-go/internal/chain"
FC "github.com/IBM/fp-go/internal/functor"
) )
func MonadAp[GAB ~func(A) B, B, A any](fab GAB, fa A) B { func MonadAp[GAB ~func(A) B, B, A any](fab GAB, fa A) B {
@@ -51,3 +52,11 @@ func MonadChainFirst[GAB ~func(A) B, A, B any](fa A, f GAB) A {
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A { func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f) return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
} }
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
return FC.MonadFlap(MonadMap[func(GAB) B, GAB, B], fab, a)
}
func Flap[GAB ~func(A) B, A, B any](a A) func(GAB) B {
return F.Bind2nd(MonadFlap[GAB, A, B], a)
}

View File

@@ -63,3 +63,11 @@ func MonadChainFirst[A, B any](fa A, f func(A) B) A {
func ChainFirst[A, B any](f func(A) B) func(A) A { func ChainFirst[A, B any](f func(A) B) func(A) A {
return G.ChainFirst(f) return G.ChainFirst(f)
} }
func MonadFlap[B, A any](fab func(A) B, a A) B {
return G.MonadFlap[func(A) B](fab, a)
}
func Flap[B, A any](a A) func(func(A) B) B {
return G.Flap[func(A) B](a)
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:08.1313362 +0200 CEST m=+0.111171801 // 2023-09-12 13:44:26.2499883 +0200 CEST m=+0.007601301
package apply package apply

View File

@@ -37,6 +37,24 @@ func MonadTraverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
return MonadTraverseReduce(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]()) return MonadTraverseReduce(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
} }
/*
*
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
HKTRB = HKT<GB>
HKTB = HKT<B>
HKTAB = HKT<func(A)B>
*/
func MonadTraverseWithIndex[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta GA,
f func(int, A) HKTB) HKTRB {
return MonadTraverseReduceWithIndex(fof, fmap, fap, ta, f, Append[GB, B], Empty[GB]())
}
func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any]( func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB, fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
@@ -49,6 +67,18 @@ func Traverse[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
} }
} }
func TraverseWithIndex[GA ~[]A, GB ~[]B, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
f func(int, A) HKTB) func(GA) HKTRB {
return func(ma GA) HKTRB {
return MonadTraverseWithIndex(fof, fmap, fap, ma, f)
}
}
func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any]( func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB, fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
@@ -71,6 +101,28 @@ func MonadTraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
}, fof(initial)) }, fof(initial))
} }
func MonadTraverseReduceWithIndex[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
ta GA,
transform func(int, A) HKTB,
reduce func(GB, B) GB,
initial GB,
) HKTRB {
mmap := fmap(F.Curry2(reduce))
return ReduceWithIndex(ta, func(idx int, r HKTRB, a A) HKTRB {
return F.Pipe2(
r,
mmap,
fap(transform(idx, a)),
)
}, fof(initial))
}
func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any]( func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB, fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB, fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
@@ -84,3 +136,17 @@ func TraverseReduce[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
return MonadTraverseReduce(fof, fmap, fap, ta, transform, reduce, initial) return MonadTraverseReduce(fof, fmap, fap, ta, transform, reduce, initial)
} }
} }
func TraverseReduceWithIndex[GA ~[]A, GB, A, B, HKTB, HKTAB, HKTRB any](
fof func(GB) HKTRB,
fmap func(func(GB) func(B) GB) func(HKTRB) HKTAB,
fap func(HKTB) func(HKTAB) HKTRB,
transform func(int, A) HKTB,
reduce func(GB, B) GB,
initial GB,
) func(GA) HKTRB {
return func(ta GA) HKTRB {
return MonadTraverseReduceWithIndex(fof, fmap, fap, ta, transform, reduce, initial)
}
}

View File

@@ -22,6 +22,16 @@ import (
FC "github.com/IBM/fp-go/internal/functor" FC "github.com/IBM/fp-go/internal/functor"
) )
func MonadAlt[LAZY ~func() HKTFA, E, A, HKTFA any](
fof func(ET.Either[E, A]) HKTFA,
fchain func(HKTFA, func(ET.Either[E, A]) HKTFA) HKTFA,
first HKTFA,
second LAZY) HKTFA {
return fchain(first, ET.Fold(F.Ignore1of1[E](second), F.Flow2(ET.Of[E, A], fof)))
}
// HKTFA = HKT<F, Either<E, A>> // HKTFA = HKT<F, Either<E, A>>
// HKTFB = HKT<F, Either<E, B>> // HKTFB = HKT<F, Either<E, B>>
func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[E, B]) HKTFB, fa HKTFA, f func(A) B) HKTFB { func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[E, B]) HKTFB, fa HKTFA, f func(A) B) HKTFB {

View File

@@ -22,8 +22,8 @@ import (
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
func FromOption[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, onNone func() E) func(ma O.Option[A]) HKTEA { func FromOption[A, HKTEA, E any](fromEither func(ET.Either[E, A]) HKTEA, onNone func() E) func(ma O.Option[A]) HKTEA {
return F.Flow2(ET.FromOption[E, A](onNone), fromEither) return F.Flow2(ET.FromOption[A](onNone), fromEither)
} }
func FromPredicate[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, pred func(A) bool, onFalse func(A) E) func(A) HKTEA { func FromPredicate[E, A, HKTEA any](fromEither func(ET.Either[E, A]) HKTEA, pred func(A) bool, onFalse func(A) E) func(A) HKTEA {
@@ -45,7 +45,7 @@ func MonadFromOption[E, A, HKTEA any](
) )
} }
func FromOptionK[E, A, B, HKTEB any]( func FromOptionK[A, E, B, HKTEB any](
fromEither func(ET.Either[E, B]) HKTEB, fromEither func(ET.Either[E, B]) HKTEB,
onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB { onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB {
// helper // helper
@@ -65,7 +65,7 @@ func ChainOptionK[A, E, B, HKTEA, HKTEB any](
fromEither func(ET.Either[E, B]) HKTEB, fromEither func(ET.Either[E, B]) HKTEB,
onNone func() E, onNone func() E,
) func(f func(A) O.Option[B]) func(ma HKTEA) HKTEB { ) func(f func(A) O.Option[B]) func(ma HKTEA) HKTEB {
return F.Flow2(FromOptionK[E, A](fromEither, onNone), F.Bind1st(F.Bind2nd[HKTEA, func(A) HKTEB, HKTEB], mchain)) return F.Flow2(FromOptionK[A](fromEither, onNone), F.Bind1st(F.Bind2nd[HKTEA, func(A) HKTEB, HKTEB], mchain))
} }
func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any]( func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any](

37
internal/functor/flap.go Normal file
View File

@@ -0,0 +1,37 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package functor
func MonadFlap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
fmap func(HKTFAB, func(FAB) B) HKTB,
fab HKTFAB,
a A,
) HKTB {
return fmap(fab, func(f FAB) B {
return f(a)
})
}
func Flap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
fmap func(HKTFAB, func(FAB) B) HKTB,
a A,
) func(HKTFAB) HKTB {
return func(fab HKTFAB) HKTB {
return MonadFlap(fmap, fab, a)
}
}

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:10.1040409 +0200 CEST m=+0.089470201 // 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
package io package io

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:10.1132645 +0200 CEST m=+0.098693801 // 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
package generic package generic
import ( import (

View File

@@ -20,6 +20,7 @@ import (
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
C "github.com/IBM/fp-go/internal/chain" C "github.com/IBM/fp-go/internal/chain"
FC "github.com/IBM/fp-go/internal/functor"
L "github.com/IBM/fp-go/internal/lazy" L "github.com/IBM/fp-go/internal/lazy"
) )
@@ -143,3 +144,11 @@ func Defer[GA ~func() A, A any](gen func() GA) GA {
return gen()() return gen()()
}) })
} }
func MonadFlap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](fab GFAB, a A) GB {
return FC.MonadFlap(MonadMap[GFAB, GB, FAB, B], fab, a)
}
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(GFAB) GB {
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
}

View File

@@ -42,6 +42,16 @@ func TraverseArray[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](
) )
} }
func TraverseArrayWithIndex[GB ~func() B, GBS ~func() BBS, AAS ~[]A, BBS ~[]B, A, B any](f func(int, A) GB) func(AAS) GBS {
return RA.TraverseWithIndex[AAS](
Of[GBS, BBS],
Map[GBS, func() func(B) BBS, BBS, func(B) BBS],
Ap[GBS, func() func(B) BBS, GB],
f,
)
}
func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS { func SequenceArray[GA ~func() A, GAS ~func() AAS, AAS ~[]A, GAAS ~[]GA, A any](tas GAAS) GAS {
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA]) return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
} }
@@ -66,6 +76,16 @@ func TraverseRecord[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K co
) )
} }
// TraverseRecordWithIndex transforms a record using an IO transform an IO of a record
func TraverseRecordWithIndex[GB ~func() B, GBS ~func() MB, MA ~map[K]A, MB ~map[K]B, K comparable, A, B any](f func(K, A) GB) func(MA) GBS {
return RR.TraverseWithIndex[MA](
Of[GBS, MB],
Map[GBS, func() func(B) MB, MB, func(B) MB],
Ap[GBS, func() func(B) MB, GB],
f,
)
}
func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS { func SequenceRecord[GA ~func() A, GAS ~func() AAS, AAS ~map[K]A, GAAS ~map[K]GA, K comparable, A any](tas GAAS) GAS {
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA]) return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])
} }

View File

@@ -84,7 +84,7 @@ func Flatten[A any](mma IO[IO[A]]) IO[A] {
return G.Flatten(mma) return G.Flatten(mma)
} }
// Memoize computes the value of the provided IO monad lazily but exactly once // Memoize computes the value of the provided [IO] monad lazily but exactly once
func Memoize[A any](ma IO[A]) IO[A] { func Memoize[A any](ma IO[A]) IO[A] {
return G.Memoize(ma) return G.Memoize(ma)
} }
@@ -138,3 +138,11 @@ var Now = G.Now[IO[time.Time]]()
func Defer[A any](gen func() IO[A]) IO[A] { func Defer[A any](gen func() IO[A]) IO[A] {
return G.Defer[IO[A]](gen) return G.Defer[IO[A]](gen)
} }
func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B] {
return G.MonadFlap[func(A) B, IO[func(A) B], IO[B], A, B](fab, a)
}
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(IO[func(A) B]) IO[B] {
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
}

View File

@@ -29,6 +29,12 @@ func TraverseArray[A, B any](f func(A) IO[B]) func([]A) IO[[]B] {
return G.TraverseArray[IO[B], IO[[]B], []A](f) return G.TraverseArray[IO[B], IO[[]B], []A](f)
} }
// TraverseArrayWithIndex applies a function returning an [IO] to all elements in an array and the
// transforms this into an [IO] of that array
func TraverseArrayWithIndex[A, B any](f func(int, A) IO[B]) func([]A) IO[[]B] {
return G.TraverseArrayWithIndex[IO[B], IO[[]B], []A](f)
}
// SequenceArray converts an array of [IO] to an [IO] of an array // SequenceArray converts an array of [IO] to an [IO] of an array
func SequenceArray[A any](tas []IO[A]) IO[[]A] { func SequenceArray[A any](tas []IO[A]) IO[[]A] {
return G.SequenceArray[IO[A], IO[[]A]](tas) return G.SequenceArray[IO[A], IO[[]A]](tas)
@@ -38,12 +44,18 @@ func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) IO[B]) I
return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f) return G.MonadTraverseRecord[IO[B], IO[map[K]B]](tas, f)
} }
// TraverseArray applies a function returning an [IO] to all elements in a record and the // TraverseRecord applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record // transforms this into an [IO] of that record
func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] { func TraverseRecord[K comparable, A, B any](f func(A) IO[B]) func(map[K]A) IO[map[K]B] {
return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f) return G.TraverseRecord[IO[B], IO[map[K]B], map[K]A](f)
} }
// TraverseRecordWithIndex applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) func(map[K]A) IO[map[K]B] {
return G.TraverseRecordWithIndex[IO[B], IO[map[K]B], map[K]A](f)
}
// SequenceRecord converts a record of [IO] to an [IO] of a record // SequenceRecord converts a record of [IO] to an [IO] of a record
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] { func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A] {
return G.SequenceRecord[IO[A], IO[map[K]A]](tas) return G.SequenceRecord[IO[A], IO[map[K]A]](tas)

View File

@@ -16,6 +16,7 @@
package file package file
import ( import (
"io"
"os" "os"
IOE "github.com/IBM/fp-go/ioeither" IOE "github.com/IBM/fp-go/ioeither"
@@ -45,3 +46,10 @@ func Remove(name string) IOE.IOEither[error, string] {
return name, os.Remove(name) return name, os.Remove(name)
}) })
} }
// Close closes an object
func Close[C io.Closer](c C) IOE.IOEither[error, any] {
return IOE.TryCatchError(func() (any, error) {
return c, c.Close()
})
}

View File

@@ -31,7 +31,7 @@ func onReadAll[R io.Reader](r R) IOE.IOEither[error, []byte] {
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] { func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
return IOE.WithResource[[]byte]( return IOE.WithResource[[]byte](
acquire, acquire,
onClose[R])( Close[R])(
onReadAll[R], onReadAll[R],
) )
} }

View File

@@ -18,7 +18,6 @@ package file
import ( import (
"os" "os"
FL "github.com/IBM/fp-go/file"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
IO "github.com/IBM/fp-go/io" IO "github.com/IBM/fp-go/io"
IOF "github.com/IBM/fp-go/io/file" IOF "github.com/IBM/fp-go/io/file"
@@ -33,7 +32,7 @@ var (
// destroy handler // destroy handler
onReleaseTempFile = F.Flow4( onReleaseTempFile = F.Flow4(
IOF.Close[*os.File], IOF.Close[*os.File],
IO.Map(FL.GetName), IO.Map((*os.File).Name),
IOE.FromIO[error, string], IOE.FromIO[error, string],
IOE.Chain(Remove), IOE.Chain(Remove),
) )

View File

@@ -38,7 +38,7 @@ func TestWithTempFileOnClosedFile(t *testing.T) {
return F.Pipe2( return F.Pipe2(
f, f,
onWriteAll[*os.File]([]byte("Carsten")), onWriteAll[*os.File]([]byte("Carsten")),
IOE.ChainFirst(F.Constant1[[]byte](onClose(f))), IOE.ChainFirst(F.Constant1[[]byte](Close(f))),
) )
}) })

View File

@@ -36,7 +36,7 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] { return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
return IOE.WithResource[[]byte]( return IOE.WithResource[[]byte](
onCreate, onCreate,
onClose[W])( Close[W])(
onWrite, onWrite,
) )
} }
@@ -46,5 +46,5 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
func Write[R any, W io.WriteCloser](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] { func Write[R any, W io.WriteCloser](acquire IOE.IOEither[error, W]) func(use func(W) IOE.IOEither[error, R]) IOE.IOEither[error, R] {
return IOE.WithResource[R]( return IOE.WithResource[R](
acquire, acquire,
onClose[W]) Close[W])
} }

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:12.0033119 +0200 CEST m=+0.096740401 // 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
package ioeither package ioeither

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:12.0246635 +0200 CEST m=+0.118092001 // 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
package generic package generic
import ( import (

View File

@@ -25,6 +25,7 @@ import (
"github.com/IBM/fp-go/internal/eithert" "github.com/IBM/fp-go/internal/eithert"
FE "github.com/IBM/fp-go/internal/fromeither" FE "github.com/IBM/fp-go/internal/fromeither"
FI "github.com/IBM/fp-go/internal/fromio" FI "github.com/IBM/fp-go/internal/fromio"
FC "github.com/IBM/fp-go/internal/functor"
IO "github.com/IBM/fp-go/io/generic" IO "github.com/IBM/fp-go/io/generic"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
@@ -290,3 +291,25 @@ func FromImpure[GA ~func() ET.Either[E, any], IMP ~func(), E any](f IMP) GA {
func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA { func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA {
return IO.Defer[GEA](gen) return IO.Defer[GEA](gen)
} }
func MonadAlt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](first GIOA, second LAZY) GIOA {
return eithert.MonadAlt(
IO.Of[GIOA],
IO.MonadChain[GIOA, GIOA],
first,
second,
)
}
func Alt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](second LAZY) func(GIOA) GIOA {
return F.Bind2nd(MonadAlt[LAZY], second)
}
func MonadFlap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](fab GEAB, a A) GEB {
return FC.MonadFlap(MonadMap[GEAB, GEB], fab, a)
}
func Flap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](a A) func(GEAB) GEB {
return FC.Flap(MonadMap[GEAB, GEB], a)
}

View File

@@ -0,0 +1,54 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
ET "github.com/IBM/fp-go/either"
M "github.com/IBM/fp-go/monoid"
)
func ApplicativeMonoid[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
m M.Monoid[A],
) M.Monoid[GEA] {
return M.ApplicativeMonoid(
MonadOf[GEA],
MonadMap[GEA, GEFA],
MonadAp[GEA, GEFA, GEA],
m,
)
}
func ApplicativeMonoidSeq[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
m M.Monoid[A],
) M.Monoid[GEA] {
return M.ApplicativeMonoid(
MonadOf[GEA],
MonadMap[GEA, GEFA],
MonadApSeq[GEA, GEFA, GEA],
m,
)
}
func ApplicativeMonoidPar[GEA ~func() ET.Either[E, A], GEFA ~func() ET.Either[E, func(A) A], E, A any](
m M.Monoid[A],
) M.Monoid[GEA] {
return M.ApplicativeMonoid(
MonadOf[GEA],
MonadMap[GEA, GEFA],
MonadApPar[GEA, GEFA, GEA],
m,
)
}

View File

@@ -0,0 +1,27 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
import (
ET "github.com/IBM/fp-go/either"
S "github.com/IBM/fp-go/semigroup"
)
func AltSemigroup[GIOA ~func() ET.Either[E, A], E, A any]() S.Semigroup[GIOA] {
return S.AltSemigroup(
MonadAlt[func() GIOA],
)
}

View File

@@ -45,6 +45,29 @@ func TraverseArray[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AA
) )
} }
// MonadTraverseArrayWithIndex transforms an array
func MonadTraverseArrayWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](tas AAS, f func(int, A) GB) GBS {
return RA.MonadTraverseWithIndex[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
tas,
f,
)
}
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~[]A, BBS ~[]B, E, A, B any](f func(int, A) GB) func(AAS) GBS {
return RA.TraverseWithIndex[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
f,
)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~[]A, GAAS ~[]GA, E, A any](tas GAAS) GAS { func SequenceArray[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~[]A, GAAS ~[]GA, E, A any](tas GAAS) GAS {
return MonadTraverseArray[GA, GAS](tas, F.Identity[GA]) return MonadTraverseArray[GA, GAS](tas, F.Identity[GA])
@@ -73,6 +96,17 @@ func TraverseRecord[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], A
) )
} }
// TraverseRecordWithIndex transforms an array
func TraverseRecordWithIndex[GB ~func() ET.Either[E, B], GBS ~func() ET.Either[E, BBS], AAS ~map[K]A, BBS ~map[K]B, K comparable, E, A, B any](f func(K, A) GB) func(AAS) GBS {
return RR.TraverseWithIndex[AAS](
Of[GBS, E, BBS],
Map[GBS, func() ET.Either[E, func(B) BBS], E, BBS, func(B) BBS],
Ap[GBS, func() ET.Either[E, func(B) BBS], GB],
f,
)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence // SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, E, A any](tas GAAS) GAS { func SequenceRecord[GA ~func() ET.Either[E, A], GAS ~func() ET.Either[E, AAS], AAS ~map[K]A, GAAS ~map[K]GA, K comparable, E, A any](tas GAAS) GAS {
return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA]) return MonadTraverseRecord[GA, GAS](tas, F.Identity[GA])

View File

@@ -19,6 +19,7 @@ import (
ET "github.com/IBM/fp-go/either" ET "github.com/IBM/fp-go/either"
I "github.com/IBM/fp-go/io" I "github.com/IBM/fp-go/io"
G "github.com/IBM/fp-go/ioeither/generic" G "github.com/IBM/fp-go/ioeither/generic"
L "github.com/IBM/fp-go/lazy"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
@@ -74,10 +75,20 @@ func ChainIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, B
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f) return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
} }
func ChainLazyK[E, A, B any](f func(A) L.Lazy[B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainIOK[IOEither[E, A], IOEither[E, B]](f)
}
// FromIO creates an [IOEither] from an [IO] instance, invoking [IO] for each invocation of [IOEither]
func FromIO[E, A any](mr I.IO[A]) IOEither[E, A] { func FromIO[E, A any](mr I.IO[A]) IOEither[E, A] {
return G.FromIO[IOEither[E, A]](mr) return G.FromIO[IOEither[E, A]](mr)
} }
// FromLazy creates an [IOEither] from a [Lazy] instance, invoking [Lazy] for each invocation of [IOEither]
func FromLazy[E, A any](mr L.Lazy[A]) IOEither[E, A] {
return G.FromIO[IOEither[E, A]](mr)
}
func MonadMap[E, A, B any](fa IOEither[E, A], f func(A) B) IOEither[E, B] { func MonadMap[E, A, B any](fa IOEither[E, A], f func(A) B) IOEither[E, B] {
return G.MonadMap[IOEither[E, A], IOEither[E, B]](fa, f) return G.MonadMap[IOEither[E, A], IOEither[E, B]](fa, f)
} }
@@ -166,27 +177,27 @@ func MonadChainTo[E, A, B any](fa IOEither[E, A], fb IOEither[E, B]) IOEither[E,
return G.MonadChainTo(fa, fb) return G.MonadChainTo(fa, fb)
} }
// ChainTo composes to the second monad ignoring the return value of the first // ChainTo composes to the second [IOEither] monad ignoring the return value of the first
func ChainTo[E, A, B any](fb IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] { func ChainTo[E, A, B any](fb IOEither[E, B]) func(IOEither[E, A]) IOEither[E, B] {
return G.ChainTo[IOEither[E, A]](fb) return G.ChainTo[IOEither[E, A]](fb)
} }
// MonadChainFirst runs the monad returned by the function but returns the result of the original monad // MonadChainFirst runs the [IOEither] monad returned by the function but returns the result of the original monad
func MonadChainFirst[E, A, B any](ma IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, A] { func MonadChainFirst[E, A, B any](ma IOEither[E, A], f func(A) IOEither[E, B]) IOEither[E, A] {
return G.MonadChainFirst(ma, f) return G.MonadChainFirst(ma, f)
} }
// ChainFirst runs the monad returned by the function but returns the result of the original monad // ChainFirst runs the [IOEither] monad returned by the function but returns the result of the original monad
func ChainFirst[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] { func ChainFirst[E, A, B any](f func(A) IOEither[E, B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ChainFirst[IOEither[E, A]](f) return G.ChainFirst[IOEither[E, A]](f)
} }
// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad // MonadChainFirstIOK runs [IO] the monad returned by the function but returns the result of the original monad
func MonadChainFirstIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, A] { func MonadChainFirstIOK[E, A, B any](ma IOEither[E, A], f func(A) I.IO[B]) IOEither[E, A] {
return G.MonadChainFirstIOK(ma, f) return G.MonadChainFirstIOK(ma, f)
} }
// ChainFirsIOKt runs the monad returned by the function but returns the result of the original monad // ChainFirstIOK runs the [IO] monad returned by the function but returns the result of the original monad
func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, A] { func ChainFirstIOK[E, A, B any](f func(A) I.IO[B]) func(IOEither[E, A]) IOEither[E, A] {
return G.ChainFirstIOK[IOEither[E, A]](f) return G.ChainFirstIOK[IOEither[E, A]](f)
} }
@@ -207,6 +218,24 @@ func FromImpure[E any](f func()) IOEither[E, any] {
} }
// Defer creates an IO by creating a brand new IO via a generator function, each time // Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[E, A any](gen func() IOEither[E, A]) IOEither[E, A] { func Defer[E, A any](gen L.Lazy[IOEither[E, A]]) IOEither[E, A] {
return G.Defer[IOEither[E, A]](gen) return G.Defer[IOEither[E, A]](gen)
} }
// MonadAlt identifies an associative operation on a type constructor
func MonadAlt[E, A any](first IOEither[E, A], second L.Lazy[IOEither[E, A]]) IOEither[E, A] {
return G.MonadAlt(first, second)
}
// Alt identifies an associative operation on a type constructor
func Alt[E, A any](second L.Lazy[IOEither[E, A]]) func(IOEither[E, A]) IOEither[E, A] {
return G.Alt(second)
}
func MonadFlap[E, B, A any](fab IOEither[E, func(A) B], a A) IOEither[E, B] {
return G.MonadFlap[IOEither[E, func(A) B], IOEither[E, B]](fab, a)
}
func Flap[E, B, A any](a A) func(IOEither[E, func(A) B]) IOEither[E, B] {
return G.Flap[IOEither[E, func(A) B], IOEither[E, B]](a)
}

42
ioeither/monoid.go Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
import (
G "github.com/IBM/fp-go/ioeither/generic"
M "github.com/IBM/fp-go/monoid"
)
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
func ApplicativeMonoid[E, A any](
m M.Monoid[A],
) M.Monoid[IOEither[E, A]] {
return G.ApplicativeMonoid[IOEither[E, A], IOEither[E, func(A) A]](m)
}
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
func ApplicativeMonoidSeq[E, A any](
m M.Monoid[A],
) M.Monoid[IOEither[E, A]] {
return G.ApplicativeMonoidSeq[IOEither[E, A], IOEither[E, func(A) A]](m)
}
// ApplicativeMonoid returns a [Monoid] that concatenates [IOEither] instances via their applicative
func ApplicativeMonoidPar[E, A any](
m M.Monoid[A],
) M.Monoid[IOEither[E, A]] {
return G.ApplicativeMonoid[IOEither[E, A], IOEither[E, func(A) A]](m)
}

42
ioeither/monoid_test.go Normal file
View File

@@ -0,0 +1,42 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
import (
"fmt"
"testing"
E "github.com/IBM/fp-go/either"
S "github.com/IBM/fp-go/string"
"github.com/stretchr/testify/assert"
)
func TestApplicativeMonoid(t *testing.T) {
m := ApplicativeMonoid[error](S.Monoid)
// good cases
assert.Equal(t, E.Of[error]("ab"), m.Concat(Of[error]("a"), Of[error]("b"))())
assert.Equal(t, E.Of[error]("a"), m.Concat(Of[error]("a"), m.Empty())())
assert.Equal(t, E.Of[error]("b"), m.Concat(m.Empty(), Of[error]("b"))())
// bad cases
e1 := fmt.Errorf("e1")
e2 := fmt.Errorf("e1")
assert.Equal(t, E.Left[string](e1), m.Concat(Left[string](e1), Of[error]("b"))())
assert.Equal(t, E.Left[string](e1), m.Concat(Left[string](e1), Left[string](e2))())
assert.Equal(t, E.Left[string](e2), m.Concat(Of[error]("a"), Left[string](e2))())
}

26
ioeither/semigroup.go Normal file
View File

@@ -0,0 +1,26 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
import (
G "github.com/IBM/fp-go/ioeither/generic"
S "github.com/IBM/fp-go/semigroup"
)
// AltSemigroup is a [Semigroup] that tries the first item and then the second one using an alternative
func AltSemigroup[E, A any]() S.Semigroup[IOEither[E, A]] {
return G.AltSemigroup[IOEither[E, A]]()
}

View File

@@ -24,6 +24,11 @@ func TraverseArray[E, A, B any](f func(A) IOEither[E, B]) func([]A) IOEither[E,
return G.TraverseArray[IOEither[E, B], IOEither[E, []B], []A](f) return G.TraverseArray[IOEither[E, B], IOEither[E, []B], []A](f)
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[E, A, B any](f func(int, A) IOEither[E, B]) func([]A) IOEither[E, []B] {
return G.TraverseArrayWithIndex[IOEither[E, B], IOEither[E, []B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[E, A any](ma []IOEither[E, A]) IOEither[E, []A] { func SequenceArray[E, A any](ma []IOEither[E, A]) IOEither[E, []A] {
return G.SequenceArray[IOEither[E, A], IOEither[E, []A]](ma) return G.SequenceArray[IOEither[E, A], IOEither[E, []A]](ma)
@@ -34,6 +39,11 @@ func TraverseRecord[K comparable, E, A, B any](f func(A) IOEither[E, B]) func(ma
return G.TraverseRecord[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f) return G.TraverseRecord[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
} }
// TraverseRecordWithIndex transforms a record
func TraverseRecordWithIndex[K comparable, E, A, B any](f func(K, A) IOEither[E, B]) func(map[K]A) IOEither[E, map[K]B] {
return G.TraverseRecordWithIndex[IOEither[E, B], IOEither[E, map[K]B], map[K]A](f)
}
// SequenceRecord converts a homogeneous sequence of either into an either of sequence // SequenceRecord converts a homogeneous sequence of either into an either of sequence
func SequenceRecord[K comparable, E, A any](ma map[K]IOEither[E, A]) IOEither[E, map[K]A] { func SequenceRecord[K comparable, E, A any](ma map[K]IOEither[E, A]) IOEither[E, map[K]A] {
return G.SequenceRecord[IOEither[E, A], IOEither[E, map[K]A]](ma) return G.SequenceRecord[IOEither[E, A], IOEither[E, map[K]A]](ma)

37
ioeither/traverse_test.go Normal file
View File

@@ -0,0 +1,37 @@
// Copyright (c) 2023 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package ioeither
import (
"fmt"
"testing"
A "github.com/IBM/fp-go/array"
E "github.com/IBM/fp-go/either"
"github.com/stretchr/testify/assert"
)
func TestTraverseArray(t *testing.T) {
src := A.From("A", "B")
trfrm := TraverseArrayWithIndex(func(idx int, data string) IOEither[error, string] {
return Of[error](fmt.Sprintf("idx: %d, data: %s", idx, data))
})
assert.Equal(t, E.Of[error](A.From("idx: 0, data: A", "idx: 1, data: B")), trfrm(src)())
}

View File

@@ -24,6 +24,11 @@ func TraverseArray[A, B any](f func(A) IOOption[B]) func([]A) IOOption[[]B] {
return G.TraverseArray[IOOption[B], IOOption[[]B], []A](f) return G.TraverseArray[IOOption[B], IOOption[[]B], []A](f)
} }
// TraverseArrayWithIndex transforms an array
func TraverseArrayWithIndex[A, B any](f func(int, A) IOOption[B]) func([]A) IOOption[[]B] {
return G.TraverseArrayWithIndex[IOOption[B], IOOption[[]B], []A](f)
}
// SequenceArray converts a homogeneous sequence of either into an either of sequence // SequenceArray converts a homogeneous sequence of either into an either of sequence
func SequenceArray[A any](ma []IOOption[A]) IOOption[[]A] { func SequenceArray[A any](ma []IOOption[A]) IOOption[[]A] {
return G.SequenceArray[IOOption[A], IOOption[[]A], []IOOption[A], []A, A](ma) return G.SequenceArray[IOOption[A], IOOption[[]A], []IOOption[A], []A, A](ma)

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:14.0582736 +0200 CEST m=+0.248503201 // 2023-09-12 13:44:32.1514823 +0200 CEST m=+0.098931001
package iooption package iooption

View File

@@ -1,6 +1,6 @@
// Code generated by go generate; DO NOT EDIT. // Code generated by go generate; DO NOT EDIT.
// This file was generated by robots at // This file was generated by robots at
// 2023-08-17 22:59:14.0642289 +0200 CEST m=+0.254458501 // 2023-09-12 13:44:32.1546277 +0200 CEST m=+0.102076401
package generic package generic
import ( import (

View File

@@ -18,6 +18,7 @@ package generic
import ( import (
"time" "time"
ET "github.com/IBM/fp-go/either"
F "github.com/IBM/fp-go/function" F "github.com/IBM/fp-go/function"
FI "github.com/IBM/fp-go/internal/fromio" FI "github.com/IBM/fp-go/internal/fromio"
"github.com/IBM/fp-go/internal/optiont" "github.com/IBM/fp-go/internal/optiont"
@@ -55,6 +56,21 @@ func FromOption[GA ~func() O.Option[A], A any](o O.Option[A]) GA {
return IO.Of[GA](o) return IO.Of[GA](o)
} }
func FromEither[GA ~func() O.Option[A], E, A any](e ET.Either[E, A]) GA {
return F.Pipe2(
e,
ET.ToOption[E, A],
FromOption[GA],
)
}
func FromIOEither[GA ~func() O.Option[A], GEA ~func() ET.Either[E, A], E, A any](ioe GEA) GA {
return F.Pipe1(
ioe,
IO.Map[GEA, GA](ET.ToOption[E, A]),
)
}
func MonadMap[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA, f func(A) B) GB { func MonadMap[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA, f func(A) B) GB {
return optiont.MonadMap(IO.MonadMap[GA, GB, O.Option[A], O.Option[B]], fa, f) return optiont.MonadMap(IO.MonadMap[GA, GB, O.Option[A], O.Option[B]], fa, f)
} }

View File

@@ -28,6 +28,13 @@ func TraverseArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]A, GB
) )
} }
func TraverseArrayWithIndex[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]A, GB ~[]B, A, B any](f func(int, A) TB) func(GA) TBS {
return F.Flow2(
I.TraverseArrayWithIndex[TB, func() []O.Option[B], GA](f),
I.Map[func() []O.Option[B], TBS](O.SequenceArrayG[GB, []O.Option[B], B]),
)
}
func SequenceArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]TB, GB ~[]B, A, B any](ma GA) TBS { func SequenceArray[TB ~func() O.Option[B], TBS ~func() O.Option[GB], GA ~[]TB, GB ~[]B, A, B any](ma GA) TBS {
return TraverseArray[TB, TBS, GA](F.Identity[TB])(ma) return TraverseArray[TB, TBS, GA](F.Identity[TB])(ma)
} }

View File

@@ -16,7 +16,9 @@
package iooption package iooption
import ( import (
ET "github.com/IBM/fp-go/either"
I "github.com/IBM/fp-go/io" I "github.com/IBM/fp-go/io"
IOE "github.com/IBM/fp-go/ioeither"
G "github.com/IBM/fp-go/iooption/generic" G "github.com/IBM/fp-go/iooption/generic"
O "github.com/IBM/fp-go/option" O "github.com/IBM/fp-go/option"
) )
@@ -117,7 +119,7 @@ func Memoize[A any](ma IOOption[A]) IOOption[A] {
return G.Memoize(ma) return G.Memoize(ma)
} }
// Fold convers an IOOption into an IO // Fold convers an [IOOption] into an [IO]
func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption[A]) I.IO[B] { func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption[A]) I.IO[B] {
return G.Fold[IOOption[A]](onNone, onSome) return G.Fold[IOOption[A]](onNone, onSome)
} }
@@ -126,3 +128,13 @@ func Fold[A, B any](onNone func() I.IO[B], onSome func(A) I.IO[B]) func(IOOption
func Defer[A any](gen func() IOOption[A]) IOOption[A] { func Defer[A any](gen func() IOOption[A]) IOOption[A] {
return G.Defer[IOOption[A]](gen) return G.Defer[IOOption[A]](gen)
} }
// FromIOEither converts an [IOEither] into an [IOOption]
func FromIOEither[E, A any](ioe IOE.IOEither[E, A]) IOOption[A] {
return G.FromIOEither[IOOption[A]](ioe)
}
// FromEither converts an [Either] into an [IOOption]
func FromEither[E, A any](e ET.Either[E, A]) IOOption[A] {
return G.FromEither[IOOption[A]](e)
}

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 stateless
import (
"testing"
F "github.com/IBM/fp-go/function"
)
func BenchmarkMulti(b *testing.B) {
// run the Fib function b.N times
for n := 0; n < b.N; n++ {
single()
}
}
func single() int64 {
length := 10000
nums := make([]int, 0, length)
for i := 0; i < length; i++ {
nums = append(nums, i+1)
}
return F.Pipe6(
nums,
FromArray[int],
Filter(func(n int) bool {
return n%2 == 0
}),
Map(func(t int) int64 {
return int64(t)
}),
Filter(func(t int64) bool {
n := t
for n/10 != 0 {
if n%10 == 4 {
return false
}
n = n / 10
}
return true
}),
Map(func(t int64) int {
return int(t)
}),
Reduce(func(n int64, r int) int64 {
return n + int64(r)
}, int64(0)),
)
}

View File

@@ -82,6 +82,7 @@ func Map[GV ~func() O.Option[T.Tuple2[GV, V]], GU ~func() O.Option[T.Tuple2[GU,
m, m,
) )
} }
m = O.Map(T.Map2(recurse, f)) m = O.Map(T.Map2(recurse, f))
return recurse return recurse

View File

@@ -29,6 +29,12 @@ func TraverseArray[A, B any](f func(A) Lazy[B]) func([]A) Lazy[[]B] {
return G.TraverseArray[Lazy[B], Lazy[[]B], []A](f) return G.TraverseArray[Lazy[B], Lazy[[]B], []A](f)
} }
// TraverseArrayWithIndex applies a function returning an [IO] to all elements in an array and the
// transforms this into an [IO] of that array
func TraverseArrayWithIndex[A, B any](f func(int, A) Lazy[B]) func([]A) Lazy[[]B] {
return G.TraverseArrayWithIndex[Lazy[B], Lazy[[]B], []A](f)
}
// SequenceArray converts an array of [IO] to an [IO] of an array // SequenceArray converts an array of [IO] to an [IO] of an array
func SequenceArray[A any](tas []Lazy[A]) Lazy[[]A] { func SequenceArray[A any](tas []Lazy[A]) Lazy[[]A] {
return G.SequenceArray[Lazy[A], Lazy[[]A]](tas) return G.SequenceArray[Lazy[A], Lazy[[]A]](tas)
@@ -38,12 +44,18 @@ func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f func(A) Lazy[B])
return G.MonadTraverseRecord[Lazy[B], Lazy[map[K]B]](tas, f) return G.MonadTraverseRecord[Lazy[B], Lazy[map[K]B]](tas, f)
} }
// TraverseArray applies a function returning an [IO] to all elements in a record and the // TraverseRecord applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record // transforms this into an [IO] of that record
func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] { func TraverseRecord[K comparable, A, B any](f func(A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
return G.TraverseRecord[Lazy[B], Lazy[map[K]B], map[K]A](f) return G.TraverseRecord[Lazy[B], Lazy[map[K]B], map[K]A](f)
} }
// TraverseRecord applies a function returning an [IO] to all elements in a record and the
// transforms this into an [IO] of that record
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) Lazy[B]) func(map[K]A) Lazy[map[K]B] {
return G.TraverseRecordWithIndex[Lazy[B], Lazy[map[K]B], map[K]A](f)
}
// SequenceRecord converts a record of [IO] to an [IO] of a record // SequenceRecord converts a record of [IO] to an [IO] of a record
func SequenceRecord[K comparable, A any](tas map[K]Lazy[A]) Lazy[map[K]A] { func SequenceRecord[K comparable, A any](tas map[K]Lazy[A]) Lazy[map[K]A] {
return G.SequenceRecord[Lazy[A], Lazy[map[K]A]](tas) return G.SequenceRecord[Lazy[A], Lazy[map[K]A]](tas)

58
monoid/alt.go Normal file
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 monoid
import (
S "github.com/IBM/fp-go/semigroup"
)
func AlternativeMonoid[A, HKTA, HKTFA any, LAZYHKTA ~func() HKTA](
fof func(A) HKTA,
fmap func(HKTA, func(A) func(A) A) HKTFA,
fap func(HKTFA, HKTA) HKTA,
falt func(HKTA, LAZYHKTA) HKTA,
m Monoid[A],
) Monoid[HKTA] {
sg := ApplicativeMonoid(fof, fmap, fap, m)
return MakeMonoid(
func(first, second HKTA) HKTA {
snd := func() HKTA { return second }
return falt(sg.Concat(first, second), func() HKTA {
return falt(first, snd)
})
},
sg.Empty(),
)
}
func AltMonoid[HKTA any, LAZYHKTA ~func() HKTA](
fzero LAZYHKTA,
falt func(HKTA, LAZYHKTA) HKTA,
) Monoid[HKTA] {
return MakeMonoid(
S.AltSemigroup(falt).Concat,
fzero(),
)
}

View File

@@ -20,15 +20,15 @@ import (
) )
func ApplicativeMonoid[A, HKTA, HKTFA any]( func ApplicativeMonoid[A, HKTA, HKTFA any](
_of func(A) HKTA, fof func(A) HKTA,
_map func(HKTA, func(A) func(A) A) HKTFA, fmap func(HKTA, func(A) func(A) A) HKTFA,
_ap func(HKTFA, HKTA) HKTA, fap func(HKTFA, HKTA) HKTA,
m Monoid[A], m Monoid[A],
) Monoid[HKTA] { ) Monoid[HKTA] {
return MakeMonoid( return MakeMonoid(
S.ApplySemigroup[A](_map, _ap, m).Concat, S.ApplySemigroup[A](fmap, fap, m).Concat,
_of(m.Empty()), fof(m.Empty()),
) )
} }

View File

@@ -67,7 +67,7 @@ func Modify[S, A any](f func(A) A) func(Iso[S, A]) func(S) S {
} }
// Wrap wraps the value // Wrap wraps the value
func Unwrap[S, A any](s S) func(Iso[S, A]) A { func Unwrap[A, S any](s S) func(Iso[S, A]) A {
return func(sa Iso[S, A]) A { return func(sa Iso[S, A]) A {
return sa.Get(s) return sa.Get(s)
} }
@@ -81,8 +81,8 @@ func Wrap[S, A any](a A) func(Iso[S, A]) S {
} }
// From wraps the value // From wraps the value
func To[S, A any](s S) func(Iso[S, A]) A { func To[A, S any](s S) func(Iso[S, A]) A {
return Unwrap[S, A](s) return Unwrap[A, S](s)
} }
// To unwraps the value // To unwraps the value

View File

@@ -121,7 +121,7 @@ func Compose[S, A, B any](ab Lens[A, B]) func(Lens[S, A]) Lens[S, B] {
// the getter returns an `Option[B]` because the container `A` could already be an option // the getter returns an `Option[B]` because the container `A` could already be an option
// if the setter is invoked with `Some[B]` then the value of `B` will be set, potentially on a default value of `A` if `A` did not exist // if the setter is invoked with `Some[B]` then the value of `B` will be set, potentially on a default value of `A` if `A` did not exist
// if the setter is invoked with `None[B]` then the container `A` is reset to `None[A]` because this is the only way to remove `B` // if the setter is invoked with `None[B]` then the container `A` is reset to `None[A]` because this is the only way to remove `B`
func ComposeOption[S, A, B any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] { func ComposeOption[S, B, A any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
defa := F.Constant(defaultA) defa := F.Constant(defaultA)
return func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] { return func(ab Lens[A, B]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
foldab := O.Fold(O.None[B], F.Flow2(ab.Get, O.Some[B])) foldab := O.Fold(O.None[B], F.Flow2(ab.Get, O.Some[B]))
@@ -172,7 +172,7 @@ func ComposeOption[S, A, B any](defaultA A) func(ab Lens[A, B]) func(Lens[S, O.O
// if the setter is called with `Some[B]` and `A` does not exist, the default of 'A' is updated with `B` // if the setter is called with `Some[B]` and `A` does not exist, the default of 'A' is updated with `B`
// if the setter is called with `None[B]` and `A` does not exist this is the identity operation on 'S' // if the setter is called with `None[B]` and `A` does not exist this is the identity operation on 'S'
// if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A' // if the setter is called with `None[B]` and `A` does exist, 'B' is removed from 'A'
func ComposeOptions[S, A, B any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] { func ComposeOptions[S, B, A any](defaultA A) func(ab Lens[A, O.Option[B]]) func(Lens[S, O.Option[A]]) Lens[S, O.Option[B]] {
defa := F.Constant(defaultA) defa := F.Constant(defaultA)
noops := F.Constant(F.Identity[S]) noops := F.Constant(F.Identity[S])
noneb := O.None[B]() noneb := O.None[B]()

View File

@@ -209,7 +209,7 @@ func TestComposeOption(t *testing.T) {
// compose lenses // compose lenses
lens := F.Pipe1( lens := F.Pipe1(
inner, inner,
ComposeOption[Outer, *Inner, int](defaultInner)(value), ComposeOption[Outer, int](defaultInner)(value),
) )
outer1 := Outer{inner: &Inner{Value: 1, Foo: "a"}} outer1 := Outer{inner: &Inner{Value: 1, Foo: "a"}}
// the checks // the checks
@@ -235,7 +235,7 @@ func TestComposeOptions(t *testing.T) {
// compose lenses // compose lenses
lens := F.Pipe1( lens := F.Pipe1(
inner, inner,
ComposeOptions[OuterOpt, *InnerOpt, *int](defaultInner)(value), ComposeOptions[OuterOpt, *int](defaultInner)(value),
) )
// additional settings // additional settings
defaultValue2 := 2 defaultValue2 := 2

View File

@@ -24,7 +24,7 @@ import (
) )
// AtRecord returns a lens that focusses on a value in a record // AtRecord returns a lens that focusses on a value in a record
func AtRecord[M ~map[K]V, K comparable, V any](key K) L.Lens[M, O.Option[V]] { func AtRecord[M ~map[K]V, V any, K comparable](key K) L.Lens[M, O.Option[V]] {
addKey := F.Bind1of2(RR.UpsertAt[M, K, V])(key) addKey := F.Bind1of2(RR.UpsertAt[M, K, V])(key)
delKey := F.Bind1of1(RR.DeleteAt[M, K, V])(key) delKey := F.Bind1of1(RR.DeleteAt[M, K, V])(key)
fold := O.Fold( fold := O.Fold(
@@ -44,6 +44,6 @@ func AtRecord[M ~map[K]V, K comparable, V any](key K) L.Lens[M, O.Option[V]] {
} }
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord` // AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
func AtKey[M ~map[K]V, S any, K comparable, V any](key K) func(sa L.Lens[S, M]) L.Lens[S, O.Option[V]] { func AtKey[M ~map[K]V, S any, V any, K comparable](key K) func(sa L.Lens[S, M]) L.Lens[S, O.Option[V]] {
return L.Compose[S](AtRecord[M](key)) return L.Compose[S](AtRecord[M](key))
} }

View File

@@ -22,11 +22,11 @@ import (
) )
// AtRecord returns a lens that focusses on a value in a record // AtRecord returns a lens that focusses on a value in a record
func AtRecord[K comparable, V any](key K) L.Lens[map[K]V, O.Option[V]] { func AtRecord[V any, K comparable](key K) L.Lens[map[K]V, O.Option[V]] {
return G.AtRecord[map[K]V](key) return G.AtRecord[map[K]V](key)
} }
// AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord` // AtKey returns a `Lens` focused on a required key of a `ReadonlyRecord`
func AtKey[S any, K comparable, V any](key K) func(sa L.Lens[S, map[K]V]) L.Lens[S, O.Option[V]] { func AtKey[S any, V any, K comparable](key K) func(sa L.Lens[S, map[K]V]) L.Lens[S, O.Option[V]] {
return G.AtKey[map[K]V, S](key) return G.AtKey[map[K]V, S](key)
} }

View File

@@ -31,7 +31,7 @@ type (
func TestAtKey(t *testing.T) { func TestAtKey(t *testing.T) {
sa := F.Pipe1( sa := F.Pipe1(
L.Id[S](), L.Id[S](),
AtKey[S, string, int]("a"), AtKey[S, int]("a"),
) )
assert.Equal(t, O.Some(1), sa.Get(S{"a": 1})) assert.Equal(t, O.Some(1), sa.Get(S{"a": 1}))

View File

@@ -198,7 +198,7 @@ func TestOuterLensLaws(t *testing.T) {
eqValue := EQT.Eq[int]() eqValue := EQT.Eq[int]()
eqOptValue := O.Eq(eqValue) eqOptValue := O.Eq(eqValue)
// lens to access a value from outer // lens to access a value from outer
valueFromOuter := L.ComposeOption[*Outer, *Inner, int](&defaultInner)(valueLens)(outerLens) valueFromOuter := L.ComposeOption[*Outer, int](&defaultInner)(valueLens)(outerLens)
// try to access the value, this should get an option // try to access the value, this should get an option
assert.True(t, eqOptValue.Equals(valueFromOuter.Get(&emptyOuter), O.None[int]())) assert.True(t, eqOptValue.Equals(valueFromOuter.Get(&emptyOuter), O.None[int]()))
// update the object // update the object
@@ -234,7 +234,7 @@ func TestOuterOptLensLaws(t *testing.T) {
valueFromOuter := F.Pipe3( valueFromOuter := F.Pipe3(
valueOptLens, valueOptLens,
LI.Compose[*InnerOpt](intIso), LI.Compose[*InnerOpt](intIso),
L.ComposeOptions[*OuterOpt, *InnerOpt, int](&defaultInnerOpt), L.ComposeOptions[*OuterOpt, int](&defaultInnerOpt),
I.Ap[L.Lens[*OuterOpt, O.Option[int]]](outerOptLens), I.Ap[L.Lens[*OuterOpt, O.Option[int]]](outerOptLens),
) )

View File

@@ -24,6 +24,7 @@ func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[Option[A]] {
return S.ApplySemigroup(MonadMap[A, func(A) A], MonadAp[A, A], s) return S.ApplySemigroup(MonadMap[A, func(A) A], MonadAp[A, A], s)
} }
// ApplicativeMonoid returns a [Monoid] that concatenates [Option] instances via their applicative
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] { func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] {
return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, A], m) return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, A], m)
} }

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