mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-26 19:38:58 +02:00
Compare commits
41 Commits
v1.0.33
...
cleue-add-
Author | SHA1 | Date | |
---|---|---|---|
|
e9584bc247 | ||
|
55252c5680 | ||
|
88bf35c4af | ||
|
da3c9683eb | ||
|
08d9fed9af | ||
|
83a0c6cdef | ||
|
9da484b79e | ||
|
e46cfd89d4 | ||
|
6a4cdfa891 | ||
|
93a7e9964b | ||
|
9ef98e1ec4 | ||
|
f1a730998d | ||
|
f129297045 | ||
|
b434f1fbf4 | ||
|
756e1336dc | ||
|
c629d18bb3 | ||
|
1eefc28ba6 | ||
|
af2915d98a | ||
|
e9f9c2777f | ||
|
895862a67e | ||
|
caf0574742 | ||
|
bace6f01eb | ||
|
254c63a16f | ||
|
655c8a9b1d | ||
|
c6d6be66e0 | ||
|
e313f95865 | ||
|
5f25317f97 | ||
|
f5aa2d6c15 | ||
|
7262820624 | ||
|
c8fc10358b | ||
|
1cd167541d | ||
|
ebe94d71dc | ||
|
7ef6eb524b | ||
|
7b82e87bf3 | ||
|
e8fdbe9f87 | ||
|
226c7039de | ||
|
943ae8e009 | ||
|
44c8441b07 | ||
|
600aeae770 | ||
|
f74a407294 | ||
|
b15ab38861 |
6
.github/workflows/build.yml
vendored
6
.github/workflows/build.yml
vendored
@@ -29,7 +29,7 @@ jobs:
|
||||
go-version: [ '1.20.x', '1.21.x' ]
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
- uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up go ${{ matrix.go-version }}
|
||||
@@ -55,12 +55,12 @@ jobs:
|
||||
steps:
|
||||
# full checkout for semantic-release
|
||||
- name: Full checkout
|
||||
uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3
|
||||
uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.0
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||
uses: actions/setup-node@e33196f7422957bea03ed53f6fbb155025ffc7b8 # v3.7.0
|
||||
uses: actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65 # v4.0.0
|
||||
with:
|
||||
node-version: ${{ env.NODE_VERSION }}
|
||||
|
||||
|
13
README.md
13
README.md
@@ -14,6 +14,8 @@ go get github.com/IBM/fp-go
|
||||
|
||||
Refer to the [samples](./samples/).
|
||||
|
||||
Find API documentation [here](https://pkg.go.dev/github.com/IBM/fp-go)
|
||||
|
||||
## 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:
|
||||
@@ -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.
|
||||
|
||||
For that reason these implementations are kept in the `internal` package. These are meant to be used by the library itself or by extensions, not by end users.
|
||||
|
||||
## Map/Ap/Flap
|
||||
|
||||
The following table lists the relationship between some selected operators
|
||||
|
||||
| Opertator | Parameter | Monad | Result |
|
||||
| -------- | ---------------- | --------------- | -------- |
|
||||
| Map | `func(A) B` | `HKT[A]` | `HKT[B]` |
|
||||
| Chain | `func(A) HKT[B]` | `HKT[A]` | `HKT[B]` |
|
||||
| Ap | `HKT[A]` | `HKT[func(A)B]` | `HKT[B]` |
|
||||
| Flap | `A` | `HKT[func(A)B]` | `HKT[B]` |
|
||||
|
@@ -308,3 +308,11 @@ func Fold[A any](m M.Monoid[A]) func([]A) A {
|
||||
func Push[A any](a A) func([]A) []A {
|
||||
return G.Push[[]A](a)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab []func(A) B, a A) []B {
|
||||
return G.MonadFlap[func(A) B, []func(A) B, []B, A, B](fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func([]func(A) B) []B {
|
||||
return G.Flap[func(A) B, []func(A) B, []B, A, B](a)
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/array"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
"github.com/IBM/fp-go/tuple"
|
||||
@@ -250,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 {
|
||||
return F.Bind2nd(array.Push[GA, A], a)
|
||||
}
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB {
|
||||
return FC.MonadFlap(MonadMap[GFAB, GB], fab, a)
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
|
||||
return F.Bind2nd(MonadFlap[FAB, GFAB, GB, A, B], a)
|
||||
}
|
||||
|
124
array/nonempty/array.go
Normal file
124
array/nonempty/array.go
Normal file
@@ -0,0 +1,124 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package nonempty
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/array/generic"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/array"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
// NonEmptyArray represents an array with at least one element
|
||||
type NonEmptyArray[A any] []A
|
||||
|
||||
// Of constructs a single element array
|
||||
func Of[A any](first A) NonEmptyArray[A] {
|
||||
return G.Of[NonEmptyArray[A]](first)
|
||||
}
|
||||
|
||||
// From constructs a [NonEmptyArray] from a set of variadic arguments
|
||||
func From[A any](first A, data ...A) NonEmptyArray[A] {
|
||||
count := len(data)
|
||||
if count == 0 {
|
||||
return Of(first)
|
||||
}
|
||||
// allocate the requested buffer
|
||||
buffer := make(NonEmptyArray[A], count+1)
|
||||
buffer[0] = first
|
||||
copy(buffer[1:], data)
|
||||
return buffer
|
||||
}
|
||||
|
||||
func IsEmpty[A any](as NonEmptyArray[A]) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func IsNonEmpty[A any](as NonEmptyArray[A]) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](as NonEmptyArray[A], f func(a A) B) NonEmptyArray[B] {
|
||||
return G.MonadMap[NonEmptyArray[A], NonEmptyArray[B]](as, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(a A) B) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return F.Bind2nd(MonadMap[A, B], f)
|
||||
}
|
||||
|
||||
func Reduce[A, B any](f func(B, A) B, initial B) func(NonEmptyArray[A]) B {
|
||||
return func(as NonEmptyArray[A]) B {
|
||||
return array.Reduce(as, f, initial)
|
||||
}
|
||||
}
|
||||
|
||||
func Tail[A any](as NonEmptyArray[A]) []A {
|
||||
return as[1:]
|
||||
}
|
||||
|
||||
func Head[A any](as NonEmptyArray[A]) A {
|
||||
return as[0]
|
||||
}
|
||||
|
||||
func First[A any](as NonEmptyArray[A]) A {
|
||||
return as[0]
|
||||
}
|
||||
|
||||
func Last[A any](as NonEmptyArray[A]) A {
|
||||
return as[len(as)-1]
|
||||
}
|
||||
|
||||
func Size[A any](as NonEmptyArray[A]) int {
|
||||
return G.Size(as)
|
||||
}
|
||||
|
||||
func Flatten[A any](mma NonEmptyArray[NonEmptyArray[A]]) NonEmptyArray[A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](fa NonEmptyArray[A], f func(a A) NonEmptyArray[B]) NonEmptyArray[B] {
|
||||
return G.MonadChain[NonEmptyArray[A], NonEmptyArray[B]](fa, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) NonEmptyArray[B]) func(NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return G.Chain[NonEmptyArray[A], NonEmptyArray[B]](f)
|
||||
}
|
||||
|
||||
func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmptyArray[B] {
|
||||
return G.MonadAp[NonEmptyArray[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] {
|
||||
return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa)
|
||||
}
|
||||
|
||||
// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup].
|
||||
func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B {
|
||||
return func(f func(A) B) func(NonEmptyArray[A]) B {
|
||||
return func(as NonEmptyArray[A]) B {
|
||||
return array.Reduce(Tail(as), func(cur B, a A) B {
|
||||
return s.Concat(cur, f(a))
|
||||
}, f(Head(as)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fold folds the [NonEmptyArray] using the provided [Semigroup].
|
||||
func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A {
|
||||
return func(as NonEmptyArray[A]) A {
|
||||
return array.Reduce(Tail(as), s.Concat, Head(as))
|
||||
}
|
||||
}
|
109
assert/assert_test.go
Normal file
109
assert/assert_test.go
Normal file
@@ -0,0 +1,109 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package assert
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var (
|
||||
errTest = fmt.Errorf("test failure")
|
||||
|
||||
// Eq is the equal predicate checking if objects are equal
|
||||
Eq = EQ.FromEquals(assert.ObjectsAreEqual)
|
||||
)
|
||||
|
||||
func wrap1[T any](wrapped func(t assert.TestingT, expected, actual any, msgAndArgs ...any) bool, t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return func(actual T) E.Either[error, T] {
|
||||
ok := wrapped(t, expected, actual)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotEqual tests if the expected and the actual values are not equal
|
||||
func NotEqual[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.NotEqual, t, expected)
|
||||
}
|
||||
|
||||
// Equal tests if the expected and the actual values are equal
|
||||
func Equal[T any](t *testing.T, expected T) func(actual T) E.Either[error, T] {
|
||||
return wrap1(assert.Equal, t, expected)
|
||||
}
|
||||
|
||||
// Length tests if an array has the expected length
|
||||
func Length[T any](t *testing.T, expected int) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Len(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NoError validates that there is no error
|
||||
func NoError[T any](t *testing.T) func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return func(actual E.Either[error, T]) E.Either[error, T] {
|
||||
return E.MonadFold(actual, func(e error) E.Either[error, T] {
|
||||
assert.NoError(t, e)
|
||||
return E.Left[T](e)
|
||||
}, func(value T) E.Either[error, T] {
|
||||
assert.NoError(t, nil)
|
||||
return E.Right[error](value)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ArrayContains tests if a value is contained in an array
|
||||
func ArrayContains[T any](t *testing.T, expected T) func(actual []T) E.Either[error, []T] {
|
||||
return func(actual []T) E.Either[error, []T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[[]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// ContainsKey tests if a key is contained in a map
|
||||
func ContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.Contains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
||||
|
||||
// NotContainsKey tests if a key is not contained in a map
|
||||
func NotContainsKey[T any, K comparable](t *testing.T, expected K) func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
return func(actual map[K]T) E.Either[error, map[K]T] {
|
||||
ok := assert.NotContains(t, actual, expected)
|
||||
if ok {
|
||||
return E.Of[error](actual)
|
||||
}
|
||||
return E.Left[map[K]T](errTest)
|
||||
}
|
||||
}
|
59
boolean/boolean.go
Normal file
59
boolean/boolean.go
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boolean
|
||||
|
||||
import (
|
||||
EQ "github.com/IBM/fp-go/eq"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
O "github.com/IBM/fp-go/ord"
|
||||
)
|
||||
|
||||
var (
|
||||
// MonoidAny is the boolean [M.Monoid] under disjunction
|
||||
MonoidAny = M.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l || r
|
||||
},
|
||||
false,
|
||||
)
|
||||
|
||||
// MonoidAll is the boolean [M.Monoid] under conjuction
|
||||
MonoidAll = M.MakeMonoid(
|
||||
func(l, r bool) bool {
|
||||
return l && r
|
||||
},
|
||||
true,
|
||||
)
|
||||
|
||||
// Eq is the equals predicate for boolean
|
||||
Eq = EQ.FromStrictEquals[bool]()
|
||||
|
||||
// Ord is the strict ordering for boolean
|
||||
Ord = O.MakeOrd(func(l, r bool) int {
|
||||
if l {
|
||||
if r {
|
||||
return 0
|
||||
}
|
||||
return +1
|
||||
}
|
||||
if r {
|
||||
return -1
|
||||
}
|
||||
return 0
|
||||
}, func(l, r bool) bool {
|
||||
return l == r
|
||||
})
|
||||
)
|
@@ -115,16 +115,14 @@ func generateEitherize(f *os.File, i int) {
|
||||
fmt.Fprintf(f, "t%d T%d", j, j)
|
||||
}
|
||||
fmt.Fprintf(f, ") Either[error, R] {\n")
|
||||
fmt.Fprintf(f, " return TryCatchError(func() (R, error) {\n")
|
||||
fmt.Fprintf(f, " return f(")
|
||||
fmt.Fprintf(f, " return TryCatchError(f(")
|
||||
for j := 0; j < i; j++ {
|
||||
if j > 0 {
|
||||
fmt.Fprintf(f, ", ")
|
||||
}
|
||||
fmt.Fprintf(f, "t%d", j)
|
||||
}
|
||||
fmt.Fprintln(f, ")")
|
||||
fmt.Fprintln(f, " })")
|
||||
fmt.Fprintln(f, "))")
|
||||
fmt.Fprintln(f, " }")
|
||||
fmt.Fprintln(f, "}")
|
||||
}
|
||||
|
@@ -19,15 +19,14 @@ import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
IOE "github.com/IBM/fp-go/ioeither/generic"
|
||||
)
|
||||
|
||||
// withContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
// WithContext wraps an existing IOEither and performs a context check for cancellation before delegating
|
||||
func WithContext[GIO ~func() E.Either[error, A], A any](ctx context.Context, ma GIO) GIO {
|
||||
return IOE.MakeIO[GIO](func() E.Either[error, A] {
|
||||
if err := context.Cause(ctx); err != nil {
|
||||
return ET.Left[A](err)
|
||||
return E.Left[A](err)
|
||||
}
|
||||
return ma()
|
||||
})
|
||||
|
@@ -1,35 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[A, B any](f func(A) Reader[B]) func([]A) Reader[[]B] {
|
||||
return R.TraverseArray[Reader[B], Reader[[]B], []A](f)
|
||||
}
|
||||
|
||||
// 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
|
||||
func SequenceArray[A any](ma []Reader[A]) Reader[[]A] {
|
||||
return R.SequenceArray[Reader[A], Reader[[]A]](ma)
|
||||
}
|
@@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[A any](f func(context.Context) A) Reader[A] {
|
||||
return R.Curry0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.Curry1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1) func(T2) Reader[A] {
|
||||
return R.Curry2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Curry3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[A] {
|
||||
return R.Curry3[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Uncurry1[T1, A any](f func(T1) Reader[A]) func(context.Context, T1) A {
|
||||
return R.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[T1, T2, A any](f func(T1) func(T2) Reader[A]) func(context.Context, T1, T2) A {
|
||||
return R.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[A]) func(context.Context, T1, T2, T3) A {
|
||||
return R.Uncurry3(f)
|
||||
}
|
@@ -1,41 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) A) func() Reader[A] {
|
||||
return R.From0[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) A) func(T1) Reader[A] {
|
||||
return R.From1[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) A) func(T1, T2) Reader[A] {
|
||||
return R.From2[Reader[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) A) func(T1, T2, T3) Reader[A] {
|
||||
return R.From3[Reader[A]](f)
|
||||
}
|
@@ -1,58 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa Reader[A], f func(A) B) Reader[B] {
|
||||
return R.MonadMap[Reader[A], Reader[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(Reader[A]) Reader[B] {
|
||||
return R.Map[Reader[A], Reader[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma Reader[A], f func(A) Reader[B]) Reader[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) Reader[B]) func(Reader[A]) Reader[B] {
|
||||
return R.Chain[Reader[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) Reader[A] {
|
||||
return R.Of[Reader[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab Reader[func(A) B], fa Reader[A]) Reader[B] {
|
||||
return R.MonadAp[Reader[A], Reader[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa Reader[A]) func(Reader[func(A) B]) Reader[B] {
|
||||
return R.Ap[Reader[A], Reader[B], Reader[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() Reader[context.Context] {
|
||||
return R.Ask[Reader[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r Reader[A]) Reader[A] {
|
||||
return R.Asks(r)
|
||||
}
|
@@ -1,75 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result, "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1, result2)
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1, "INPUT")
|
||||
assert.Equal(t, result2, "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult, "INPUT-input: 10")
|
||||
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package reader
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[A any](a Reader[A]) Reader[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
Reader[A],
|
||||
Reader[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a Reader[A], b Reader[B]) Reader[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a Reader[A], b Reader[B], c Reader[C]) Reader[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a Reader[A], b Reader[B], c Reader[C], d Reader[D]) Reader[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
Reader[A],
|
||||
Reader[B],
|
||||
Reader[C],
|
||||
Reader[D],
|
||||
Reader[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
@@ -34,8 +34,6 @@ var (
|
||||
|
||||
func command(name string, args []string, in []byte) RE.ReaderEither[exec.CommandOutput] {
|
||||
return func(ctx context.Context) E.Either[error, exec.CommandOutput] {
|
||||
return E.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(ctx, name, args, in)
|
||||
})
|
||||
return E.TryCatchError(GE.Exec(ctx, name, args, in))
|
||||
}
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ package readereither
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/context/reader"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
RE "github.com/IBM/fp-go/readereither/generic"
|
||||
@@ -32,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderEither[A] {
|
||||
return RE.FromEither[ReaderEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.RightReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderEither[A] {
|
||||
return RE.LeftReader[R.Reader[error], ReaderEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderEither[A] {
|
||||
return RE.Left[ReaderEither[A]](l)
|
||||
}
|
||||
@@ -48,10 +39,6 @@ func Right[A any](r A) ReaderEither[A] {
|
||||
return RE.Right[ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.FromReader[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderEither[A], f func(A) B) ReaderEither[B] {
|
||||
return RE.MonadMap[ReaderEither[A], ReaderEither[B]](fa, f)
|
||||
}
|
||||
@@ -84,30 +71,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
|
||||
return RE.FromPredicate[ReaderEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) R.Reader[B], onRight func(A) R.Reader[B]) func(ReaderEither[A]) R.Reader[B] {
|
||||
return RE.Fold[ReaderEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) R.Reader[A]) func(ReaderEither[A]) R.Reader[A] {
|
||||
return RE.GetOrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderEither[A]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrElse[ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) R.Reader[error]) func(ReaderEither[A]) ReaderEither[A] {
|
||||
return RE.OrLeft[ReaderEither[A], ReaderEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderEither[context.Context] {
|
||||
return RE.Ask[ReaderEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderEither[A] {
|
||||
return RE.Asks[R.Reader[A], ReaderEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderEither[A], f func(A) ET.Either[error, B]) ReaderEither[B] {
|
||||
return RE.MonadChainEitherK[ReaderEither[A], ReaderEither[B]](ma, f)
|
||||
}
|
||||
@@ -119,3 +90,11 @@ func ChainEitherK[A, B any](f func(A) ET.Either[error, B]) func(ma ReaderEither[
|
||||
func ChainOptionK[A, B any](onNone func() error) func(func(A) O.Option[B]) func(ReaderEither[A]) ReaderEither[B] {
|
||||
return RE.ChainOptionK[ReaderEither[A], ReaderEither[B]](onNone)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab ReaderEither[func(A) B], a A) ReaderEither[B] {
|
||||
return RE.MonadFlap[ReaderEither[func(A) B], ReaderEither[B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func(ReaderEither[func(A) B]) ReaderEither[B] {
|
||||
return RE.Flap[ReaderEither[func(A) B], ReaderEither[B]](a)
|
||||
}
|
||||
|
@@ -1,36 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerio
|
||||
|
||||
import (
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
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)
|
||||
}
|
||||
|
||||
// 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
|
||||
func SequenceArray[A any](ma []ReaderIO[A]) ReaderIO[[]A] {
|
||||
return R.SequenceArray[ReaderIO[A], ReaderIO[[]A]](ma)
|
||||
}
|
@@ -1,42 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a either reader with the context as the last parameter
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[A any](f func(context.Context) IO.IO[A]) func() ReaderIO[A] {
|
||||
return R.From0[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From1[T1, A any](f func(context.Context, T1) IO.IO[A]) func(T1) ReaderIO[A] {
|
||||
return R.From1[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From2[T1, T2, A any](f func(context.Context, T1, T2) IO.IO[A]) func(T1, T2) ReaderIO[A] {
|
||||
return R.From2[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func From3[T1, T2, T3, A any](f func(context.Context, T1, T2, T3) IO.IO[A]) func(T1, T2, T3) ReaderIO[A] {
|
||||
return R.From3[ReaderIO[A]](f)
|
||||
}
|
@@ -1,59 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIO[A], f func(A) B) ReaderIO[B] {
|
||||
return R.MonadMap[ReaderIO[A], ReaderIO[B]](fa, f)
|
||||
}
|
||||
|
||||
func Map[A, B any](f func(A) B) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Map[ReaderIO[A], ReaderIO[B]](f)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderIO[A], f func(A) ReaderIO[B]) ReaderIO[B] {
|
||||
return R.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
func Chain[A, B any](f func(A) ReaderIO[B]) func(ReaderIO[A]) ReaderIO[B] {
|
||||
return R.Chain[ReaderIO[A]](f)
|
||||
}
|
||||
|
||||
func Of[A any](a A) ReaderIO[A] {
|
||||
return R.Of[ReaderIO[A]](a)
|
||||
}
|
||||
|
||||
func MonadAp[A, B any](fab ReaderIO[func(A) B], fa ReaderIO[A]) ReaderIO[B] {
|
||||
return R.MonadAp[ReaderIO[A], ReaderIO[B]](fab, fa)
|
||||
}
|
||||
|
||||
func Ap[A, B any](fa ReaderIO[A]) func(ReaderIO[func(A) B]) ReaderIO[B] {
|
||||
return R.Ap[ReaderIO[A], ReaderIO[B], ReaderIO[func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Ask() ReaderIO[context.Context] {
|
||||
return R.Ask[ReaderIO[context.Context]]()
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] {
|
||||
return R.Defer[ReaderIO[A]](gen)
|
||||
}
|
@@ -1,80 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerio
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func GoFunction(ctx context.Context, data string) IO.IO[string] {
|
||||
return func() string {
|
||||
return strings.ToUpper(data)
|
||||
}
|
||||
}
|
||||
|
||||
func GoIntFunction(ctx context.Context, data string, number int) IO.IO[string] {
|
||||
return func() string {
|
||||
return fmt.Sprintf("%s: %d", data, number)
|
||||
}
|
||||
}
|
||||
|
||||
func TestReaderFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
f := From1(GoFunction)
|
||||
|
||||
result := f("input")(ctx)
|
||||
|
||||
assert.Equal(t, result(), "INPUT")
|
||||
|
||||
}
|
||||
|
||||
func MyFinalResult(left, right string) string {
|
||||
return fmt.Sprintf("%s-%s", left, right)
|
||||
}
|
||||
|
||||
func TestReadersFrom(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
|
||||
f1 := From1(GoFunction)
|
||||
f2 := From2(GoIntFunction)
|
||||
|
||||
result1 := f1("input")(ctx)
|
||||
result2 := f2("input", 10)(ctx)
|
||||
|
||||
result3 := MyFinalResult(result1(), result2())
|
||||
|
||||
h := F.Pipe1(
|
||||
SequenceT2(f1("input"), f2("input", 10)),
|
||||
Map(T.Tupled2(MyFinalResult)),
|
||||
)
|
||||
|
||||
composedResult := h(ctx)
|
||||
|
||||
assert.Equal(t, result1(), "INPUT")
|
||||
assert.Equal(t, result2(), "input: 10")
|
||||
assert.Equal(t, result3, "INPUT-input: 10")
|
||||
|
||||
assert.Equal(t, composedResult(), "INPUT-input: 10")
|
||||
|
||||
}
|
@@ -1,57 +0,0 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerio
|
||||
|
||||
import (
|
||||
R "github.com/IBM/fp-go/readerio/generic"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[A any](a ReaderIO[A]) ReaderIO[T.Tuple1[A]] {
|
||||
return R.SequenceT1[
|
||||
ReaderIO[A],
|
||||
ReaderIO[T.Tuple1[A]],
|
||||
](a)
|
||||
}
|
||||
|
||||
func SequenceT2[A, B any](a ReaderIO[A], b ReaderIO[B]) ReaderIO[T.Tuple2[A, B]] {
|
||||
return R.SequenceT2[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[T.Tuple2[A, B]],
|
||||
](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[A, B, C any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C]) ReaderIO[T.Tuple3[A, B, C]] {
|
||||
return R.SequenceT3[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[T.Tuple3[A, B, C]],
|
||||
](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[A, B, C, D any](a ReaderIO[A], b ReaderIO[B], c ReaderIO[C], d ReaderIO[D]) ReaderIO[T.Tuple4[A, B, C, D]] {
|
||||
return R.SequenceT4[
|
||||
ReaderIO[A],
|
||||
ReaderIO[B],
|
||||
ReaderIO[C],
|
||||
ReaderIO[D],
|
||||
ReaderIO[T.Tuple4[A, B, C, D]],
|
||||
](a, b, c, d)
|
||||
}
|
37
context/readerioeither/bracket.go
Normal file
37
context/readerioeither/bracket.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
A, B, ANY any](
|
||||
|
||||
acquire ReaderIOEither[A],
|
||||
use func(A) ReaderIOEither[B],
|
||||
release func(A, E.Either[error, B]) ReaderIOEither[ANY],
|
||||
) ReaderIOEither[B] {
|
||||
return G.Bracket[ReaderIOEither[A], ReaderIOEither[B], ReaderIOEither[ANY]](
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
@@ -25,25 +25,31 @@ import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/IBM/fp-go/internal/file"
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||
)
|
||||
|
||||
var (
|
||||
openIOE = IOE.Eitherize1(os.Open)
|
||||
// Open opens a file for reading within the given context
|
||||
Open = F.Flow3(
|
||||
openIOE,
|
||||
IOEF.Open,
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
|
||||
// Remove removes a file by name
|
||||
Remove = F.Flow2(
|
||||
IOEF.Remove,
|
||||
RIOE.FromIOEither[string],
|
||||
)
|
||||
)
|
||||
|
||||
// Close closes an object
|
||||
func Close[C io.Closer](c C) RIOE.ReaderIOEither[any] {
|
||||
return RIOE.FromIOEither(func() ET.Either[error, any] {
|
||||
return ET.TryCatchError(func() (any, error) {
|
||||
return c, c.Close()
|
||||
})
|
||||
})
|
||||
return F.Pipe2(
|
||||
c,
|
||||
IOEF.Close[C],
|
||||
RIOE.FromIOEither[any],
|
||||
)
|
||||
}
|
||||
|
||||
// ReadFile reads a file in the scope of a context
|
||||
|
@@ -19,9 +19,7 @@ import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
RIO "github.com/IBM/fp-go/context/readerio"
|
||||
R "github.com/IBM/fp-go/context/readerioeither"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
J "github.com/IBM/fp-go/json"
|
||||
@@ -37,20 +35,17 @@ func getData(r RecordType) string {
|
||||
|
||||
func ExampleReadFile() {
|
||||
|
||||
data := F.Pipe4(
|
||||
data := F.Pipe3(
|
||||
ReadFile("./data/file.json"),
|
||||
R.ChainEitherK(J.Unmarshal[RecordType]),
|
||||
R.ChainFirstIOK(IO.Logf[RecordType]("Log: %v")),
|
||||
R.Map(getData),
|
||||
R.GetOrElse(F.Flow2(
|
||||
errors.ToString,
|
||||
RIO.Of[string],
|
||||
)),
|
||||
)
|
||||
|
||||
result := data(context.Background())
|
||||
|
||||
fmt.Println(result())
|
||||
|
||||
// Output: Carsten
|
||||
// Output:
|
||||
// Right[<nil>, string](Carsten)
|
||||
}
|
||||
|
52
context/readerioeither/file/tempfile.go
Normal file
52
context/readerioeither/file/tempfile.go
Normal file
@@ -0,0 +1,52 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"os"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOF "github.com/IBM/fp-go/io/file"
|
||||
IOEF "github.com/IBM/fp-go/ioeither/file"
|
||||
)
|
||||
|
||||
var (
|
||||
// onCreateTempFile creates a temp file with sensible defaults
|
||||
onCreateTempFile = CreateTemp("", "*")
|
||||
// destroy handler
|
||||
onReleaseTempFile = F.Flow4(
|
||||
IOF.Close[*os.File],
|
||||
IO.Map((*os.File).Name),
|
||||
RIOE.FromIO[string],
|
||||
RIOE.Chain(Remove),
|
||||
)
|
||||
)
|
||||
|
||||
// CreateTemp created a temp file with proper parametrization
|
||||
func CreateTemp(dir, pattern string) RIOE.ReaderIOEither[*os.File] {
|
||||
return F.Pipe2(
|
||||
IOEF.CreateTemp(dir, pattern),
|
||||
RIOE.FromIOEither[*os.File],
|
||||
RIOE.WithContext[*os.File],
|
||||
)
|
||||
}
|
||||
|
||||
// WithTempFile creates a temporary file, then invokes a callback to create a resource based on the file, then close and remove the temp file
|
||||
func WithTempFile[A any](f func(*os.File) RIOE.ReaderIOEither[A]) RIOE.ReaderIOEither[A] {
|
||||
return RIOE.WithResource[A](onCreateTempFile, onReleaseTempFile)(f)
|
||||
}
|
47
context/readerioeither/file/tempfile_test.go
Normal file
47
context/readerioeither/file/tempfile_test.go
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestWithTempFile(t *testing.T) {
|
||||
|
||||
res := WithTempFile(onWriteAll[*os.File]([]byte("Carsten")))
|
||||
|
||||
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||
}
|
||||
|
||||
func TestWithTempFileOnClosedFile(t *testing.T) {
|
||||
|
||||
res := WithTempFile(func(f *os.File) RIOE.ReaderIOEither[[]byte] {
|
||||
return F.Pipe2(
|
||||
f,
|
||||
onWriteAll[*os.File]([]byte("Carsten")),
|
||||
RIOE.ChainFirst(F.Constant1[[]byte](Close(f))),
|
||||
)
|
||||
})
|
||||
|
||||
assert.Equal(t, E.Of[error]([]byte("Carsten")), res(context.Background())())
|
||||
}
|
57
context/readerioeither/file/write.go
Normal file
57
context/readerioeither/file/write.go
Normal file
@@ -0,0 +1,57 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
|
||||
RIOE "github.com/IBM/fp-go/context/readerioeither"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
)
|
||||
|
||||
func onWriteAll[W io.Writer](data []byte) func(w W) RIOE.ReaderIOEither[[]byte] {
|
||||
return func(w W) RIOE.ReaderIOEither[[]byte] {
|
||||
return F.Pipe1(
|
||||
RIOE.TryCatch(func(ctx context.Context) func() ([]byte, error) {
|
||||
return func() ([]byte, error) {
|
||||
_, err := w.Write(data)
|
||||
return data, err
|
||||
}
|
||||
}),
|
||||
RIOE.WithContext[[]byte],
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// WriteAll uses a generator function to create a stream, writes data to it and closes it
|
||||
func WriteAll[W io.WriteCloser](data []byte) func(acquire RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||
onWrite := onWriteAll[W](data)
|
||||
return func(onCreate RIOE.ReaderIOEither[W]) RIOE.ReaderIOEither[[]byte] {
|
||||
return RIOE.WithResource[[]byte](
|
||||
onCreate,
|
||||
Close[W])(
|
||||
onWrite,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
// Write uses a generator function to create a stream, writes data to it and closes it
|
||||
func Write[R any, W io.WriteCloser](acquire RIOE.ReaderIOEither[W]) func(use func(W) RIOE.ReaderIOEither[R]) RIOE.ReaderIOEither[R] {
|
||||
return RIOE.WithResource[R](
|
||||
acquire,
|
||||
Close[W])
|
||||
}
|
@@ -2,7 +2,7 @@ package readerioeither
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:14.1022311 +0200 CEST m=+0.017763401
|
||||
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
53
context/readerioeither/generic/bracket.go
Normal file
53
context/readerioeither/generic/bracket.go
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
G "github.com/IBM/fp-go/internal/bracket"
|
||||
I "github.com/IBM/fp-go/readerio/generic"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
GA ~func(context.Context) TA,
|
||||
GB ~func(context.Context) TB,
|
||||
GANY ~func(context.Context) TANY,
|
||||
|
||||
TA ~func() E.Either[error, A],
|
||||
TB ~func() E.Either[error, B],
|
||||
TANY ~func() E.Either[error, ANY],
|
||||
|
||||
A, B, ANY any](
|
||||
|
||||
acquire GA,
|
||||
use func(A) GB,
|
||||
release func(A, E.Either[error, B]) GANY,
|
||||
) GB {
|
||||
return G.Bracket[GA, GB, GANY, E.Either[error, B], A, B](
|
||||
I.Of[GB, TB, context.Context, E.Either[error, B]],
|
||||
MonadChain[GA, GB, TA, TB, A, B],
|
||||
I.MonadChain[GB, GB, TB, TB, context.Context, E.Either[error, B], E.Either[error, B]],
|
||||
MonadChain[GANY, GB, TANY, TB, ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
@@ -2,7 +2,7 @@ package generic
|
||||
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:14.1036885 +0200 CEST m=+0.019220801
|
||||
// 2023-10-23 08:30:39.012572 +0200 CEST m=+0.008846101
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
@@ -100,6 +100,28 @@ func Map[
|
||||
return RIE.Map[GRA, GRB](f)
|
||||
}
|
||||
|
||||
func MonadMapTo[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRB ~func(context.Context) GIOB,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GIOB ~func() E.Either[error, B],
|
||||
|
||||
A, B any](fa GRA, b B) GRB {
|
||||
return RIE.MonadMapTo[GRA, GRB](fa, b)
|
||||
}
|
||||
|
||||
func MapTo[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRB ~func(context.Context) GIOB,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GIOB ~func() E.Either[error, B],
|
||||
|
||||
A, B any](b B) func(GRA) GRB {
|
||||
return RIE.MapTo[GRA, GRB](b)
|
||||
}
|
||||
|
||||
func MonadChain[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRB ~func(context.Context) GIOB,
|
||||
@@ -410,10 +432,10 @@ func FromIOEither[
|
||||
|
||||
func FromIO[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
|
||||
GIOB ~func() A,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
|
||||
A any](t GIOB) GRA {
|
||||
return RIE.FromIO[GRA](t)
|
||||
}
|
||||
@@ -458,6 +480,34 @@ func ChainIOK[
|
||||
return RIE.ChainIOK[GRA, GRB](f)
|
||||
}
|
||||
|
||||
func MonadChainReaderIOK[
|
||||
GRB ~func(context.Context) GIOB,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRIO ~func(context.Context) GIO,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GIOB ~func() E.Either[error, B],
|
||||
|
||||
GIO ~func() B,
|
||||
|
||||
A, B any](ma GRA, f func(A) GRIO) GRB {
|
||||
return RIE.MonadChainReaderIOK[GRA, GRB](ma, f)
|
||||
}
|
||||
|
||||
func ChainReaderIOK[
|
||||
GRB ~func(context.Context) GIOB,
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GRIO ~func(context.Context) GIO,
|
||||
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GIOB ~func() E.Either[error, B],
|
||||
|
||||
GIO ~func() B,
|
||||
|
||||
A, B any](f func(A) GRIO) func(ma GRA) GRB {
|
||||
return RIE.ChainReaderIOK[GRA, GRB](f)
|
||||
}
|
||||
|
||||
func MonadChainFirstIOK[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
@@ -521,7 +571,7 @@ func Timer[
|
||||
](delay time.Duration) GRA {
|
||||
return F.Pipe2(
|
||||
IO.Now[func() time.Time](),
|
||||
FromIO[GRA, GIOA, func() time.Time],
|
||||
FromIO[GRA, func() time.Time],
|
||||
Delay[GRA](delay),
|
||||
)
|
||||
}
|
||||
@@ -551,3 +601,74 @@ func MonadAlt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.
|
||||
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)
|
||||
}
|
||||
|
44
context/readerioeither/generic/sync.go
Normal file
44
context/readerioeither/generic/sync.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
E "github.com/IBM/fp-go/either"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[
|
||||
GRA ~func(context.Context) GIOA,
|
||||
GIOA ~func() E.Either[error, A],
|
||||
GRCANCEL ~func(context.Context) GIOCANCEL,
|
||||
GIOCANCEL ~func() E.Either[error, context.CancelFunc],
|
||||
A any](lock GRCANCEL) func(fa GRA) GRA {
|
||||
|
||||
type GRANY func(ctx context.Context) func() E.Either[error, any]
|
||||
type IOANY func() any
|
||||
|
||||
return F.Flow2(
|
||||
F.Constant1[context.CancelFunc, GRA],
|
||||
WithResource[GRA, GRCANCEL, GRANY](lock, F.Flow2(
|
||||
IO.FromImpure[IOANY, context.CancelFunc],
|
||||
FromIO[GRANY, IOANY],
|
||||
)),
|
||||
)
|
||||
}
|
@@ -17,6 +17,7 @@ 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"
|
||||
)
|
||||
|
||||
@@ -34,3 +35,22 @@ func ApplicativeMonoidSeq[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||
func ApplicativeMonoidPar[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||
return G.ApplicativeMonoidPar[ReaderIOEither[A], ReaderIOEither[func(A) A]](m)
|
||||
}
|
||||
|
||||
// AlternativeMonoid is the alternative [Monoid] for [ReaderIOEither]
|
||||
func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] {
|
||||
return M.AlternativeMonoid(
|
||||
Of[A],
|
||||
MonadMap[A, func(A) A],
|
||||
MonadAp[A, A],
|
||||
MonadAlt[A],
|
||||
m,
|
||||
)
|
||||
}
|
||||
|
||||
// AltMonoid is the alternative [Monoid] for an [ReaderIOEither]
|
||||
func AltMonoid[A any](zero L.Lazy[ReaderIOEither[A]]) M.Monoid[ReaderIOEither[A]] {
|
||||
return M.AltMonoid(
|
||||
zero,
|
||||
MonadAlt[A],
|
||||
)
|
||||
}
|
||||
|
@@ -19,8 +19,6 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
R "github.com/IBM/fp-go/context/reader"
|
||||
RIO "github.com/IBM/fp-go/context/readerio"
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
@@ -33,14 +31,6 @@ func FromEither[A any](e ET.Either[error, A]) ReaderIOEither[A] {
|
||||
return G.FromEither[ReaderIOEither[A]](e)
|
||||
}
|
||||
|
||||
func RightReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.RightReader[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func LeftReader[A any](l R.Reader[error]) ReaderIOEither[A] {
|
||||
return G.LeftReader[ReaderIOEither[A]](l)
|
||||
}
|
||||
|
||||
func Left[A any](l error) ReaderIOEither[A] {
|
||||
return G.Left[ReaderIOEither[A]](l)
|
||||
}
|
||||
@@ -49,10 +39,6 @@ func Right[A any](r A) ReaderIOEither[A] {
|
||||
return G.Right[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func FromReader[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.FromReader[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadMap[A, B any](fa ReaderIOEither[A], f func(A) B) ReaderIOEither[B] {
|
||||
return G.MonadMap[ReaderIOEither[A], ReaderIOEither[B]](fa, f)
|
||||
}
|
||||
@@ -61,6 +47,14 @@ func Map[A, B any](f func(A) B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return G.Map[ReaderIOEither[A], ReaderIOEither[B]](f)
|
||||
}
|
||||
|
||||
func MonadMapTo[A, B any](fa ReaderIOEither[A], b B) ReaderIOEither[B] {
|
||||
return G.MonadMapTo[ReaderIOEither[A], ReaderIOEither[B]](fa, b)
|
||||
}
|
||||
|
||||
func MapTo[A, B any](b B) func(ReaderIOEither[A]) ReaderIOEither[B] {
|
||||
return G.MapTo[ReaderIOEither[A], ReaderIOEither[B]](b)
|
||||
}
|
||||
|
||||
func MonadChain[A, B any](ma ReaderIOEither[A], f func(A) ReaderIOEither[B]) ReaderIOEither[B] {
|
||||
return G.MonadChain(ma, f)
|
||||
}
|
||||
@@ -95,30 +89,14 @@ func FromPredicate[A any](pred func(A) bool, onFalse func(A) error) func(A) Read
|
||||
return G.FromPredicate[ReaderIOEither[A]](pred, onFalse)
|
||||
}
|
||||
|
||||
func Fold[A, B any](onLeft func(error) RIO.ReaderIO[B], onRight func(A) RIO.ReaderIO[B]) func(ReaderIOEither[A]) RIO.ReaderIO[B] {
|
||||
return G.Fold[RIO.ReaderIO[B], ReaderIOEither[A]](onLeft, onRight)
|
||||
}
|
||||
|
||||
func GetOrElse[A any](onLeft func(error) RIO.ReaderIO[A]) func(ReaderIOEither[A]) RIO.ReaderIO[A] {
|
||||
return G.GetOrElse[RIO.ReaderIO[A], ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrElse[A any](onLeft func(error) ReaderIOEither[A]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.OrElse[ReaderIOEither[A]](onLeft)
|
||||
}
|
||||
|
||||
func OrLeft[A any](onLeft func(error) RIO.ReaderIO[error]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.OrLeft[ReaderIOEither[A], RIO.ReaderIO[error]](onLeft)
|
||||
}
|
||||
|
||||
func Ask() ReaderIOEither[context.Context] {
|
||||
return G.Ask[ReaderIOEither[context.Context]]()
|
||||
}
|
||||
|
||||
func Asks[A any](r R.Reader[A]) ReaderIOEither[A] {
|
||||
return G.Asks[ReaderIOEither[A]](r)
|
||||
}
|
||||
|
||||
func MonadChainEitherK[A, B any](ma ReaderIOEither[A], f func(A) ET.Either[error, B]) ReaderIOEither[B] {
|
||||
return G.MonadChainEitherK[ReaderIOEither[A], ReaderIOEither[B]](ma, f)
|
||||
}
|
||||
@@ -147,6 +125,10 @@ func FromIO[A any](t IO.IO[A]) ReaderIOEither[A] {
|
||||
return G.FromIO[ReaderIOEither[A]](t)
|
||||
}
|
||||
|
||||
func FromLazy[A any](t L.Lazy[A]) ReaderIOEither[A] {
|
||||
return G.FromIO[ReaderIOEither[A]](t)
|
||||
}
|
||||
|
||||
// Never returns a 'ReaderIOEither' that never returns, except if its context gets canceled
|
||||
func Never[A any]() ReaderIOEither[A] {
|
||||
return G.Never[ReaderIOEither[A]]()
|
||||
@@ -201,3 +183,24 @@ func MonadAlt[A any](first ReaderIOEither[A], second L.Lazy[ReaderIOEither[A]])
|
||||
func Alt[A any](second L.Lazy[ReaderIOEither[A]]) func(ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.Alt(second)
|
||||
}
|
||||
|
||||
// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
|
||||
// The context used to compute the value is the context of the first call, so do not use this
|
||||
// method if the value has a functional dependency on the content of the context
|
||||
func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.Memoize[ReaderIOEither[A]](rdr)
|
||||
}
|
||||
|
||||
// Flatten converts a nested [ReaderIOEither] into a [ReaderIOEither]
|
||||
func Flatten[
|
||||
A any](rdr ReaderIOEither[ReaderIOEither[A]]) ReaderIOEither[A] {
|
||||
return G.Flatten[ReaderIOEither[ReaderIOEither[A]]](rdr)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab ReaderIOEither[func(A) B], a A) ReaderIOEither[B] {
|
||||
return G.MonadFlap[ReaderIOEither[func(A) B], ReaderIOEither[B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func(ReaderIOEither[func(A) B]) ReaderIOEither[B] {
|
||||
return G.Flap[ReaderIOEither[func(A) B], ReaderIOEither[B]](a)
|
||||
}
|
||||
|
@@ -162,3 +162,125 @@ func TestRegularApply(t *testing.T) {
|
||||
res := applied(context.Background())()
|
||||
assert.Equal(t, E.Of[error]("CARSTEN"), res)
|
||||
}
|
||||
|
||||
func TestWithResourceNoErrors(t *testing.T) {
|
||||
var countAcquire, countBody, countRelease int
|
||||
|
||||
acquire := FromLazy(func() int {
|
||||
countAcquire++
|
||||
return countAcquire
|
||||
})
|
||||
|
||||
release := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countRelease++
|
||||
return countRelease
|
||||
})
|
||||
}
|
||||
|
||||
body := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countBody++
|
||||
return countBody
|
||||
})
|
||||
}
|
||||
|
||||
resRIOE := WithResource[int](acquire, release)(body)
|
||||
|
||||
res := resRIOE(context.Background())()
|
||||
|
||||
assert.Equal(t, 1, countAcquire)
|
||||
assert.Equal(t, 1, countBody)
|
||||
assert.Equal(t, 1, countRelease)
|
||||
assert.Equal(t, E.Of[error](1), res)
|
||||
}
|
||||
|
||||
func TestWithResourceErrorInBody(t *testing.T) {
|
||||
var countAcquire, countBody, countRelease int
|
||||
|
||||
acquire := FromLazy(func() int {
|
||||
countAcquire++
|
||||
return countAcquire
|
||||
})
|
||||
|
||||
release := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countRelease++
|
||||
return countRelease
|
||||
})
|
||||
}
|
||||
|
||||
err := fmt.Errorf("error in body")
|
||||
body := func(int) ReaderIOEither[int] {
|
||||
return Left[int](err)
|
||||
}
|
||||
|
||||
resRIOE := WithResource[int](acquire, release)(body)
|
||||
|
||||
res := resRIOE(context.Background())()
|
||||
|
||||
assert.Equal(t, 1, countAcquire)
|
||||
assert.Equal(t, 0, countBody)
|
||||
assert.Equal(t, 1, countRelease)
|
||||
assert.Equal(t, E.Left[int](err), res)
|
||||
}
|
||||
|
||||
func TestWithResourceErrorInAcquire(t *testing.T) {
|
||||
var countAcquire, countBody, countRelease int
|
||||
|
||||
err := fmt.Errorf("error in acquire")
|
||||
acquire := Left[int](err)
|
||||
|
||||
release := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countRelease++
|
||||
return countRelease
|
||||
})
|
||||
}
|
||||
|
||||
body := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countBody++
|
||||
return countBody
|
||||
})
|
||||
}
|
||||
|
||||
resRIOE := WithResource[int](acquire, release)(body)
|
||||
|
||||
res := resRIOE(context.Background())()
|
||||
|
||||
assert.Equal(t, 0, countAcquire)
|
||||
assert.Equal(t, 0, countBody)
|
||||
assert.Equal(t, 0, countRelease)
|
||||
assert.Equal(t, E.Left[int](err), res)
|
||||
}
|
||||
|
||||
func TestWithResourceErrorInRelease(t *testing.T) {
|
||||
var countAcquire, countBody, countRelease int
|
||||
|
||||
acquire := FromLazy(func() int {
|
||||
countAcquire++
|
||||
return countAcquire
|
||||
})
|
||||
|
||||
err := fmt.Errorf("error in release")
|
||||
release := func(int) ReaderIOEither[int] {
|
||||
return Left[int](err)
|
||||
}
|
||||
|
||||
body := func(int) ReaderIOEither[int] {
|
||||
return FromLazy(func() int {
|
||||
countBody++
|
||||
return countBody
|
||||
})
|
||||
}
|
||||
|
||||
resRIOE := WithResource[int](acquire, release)(body)
|
||||
|
||||
res := resRIOE(context.Background())()
|
||||
|
||||
assert.Equal(t, 1, countAcquire)
|
||||
assert.Equal(t, 1, countBody)
|
||||
assert.Equal(t, 0, countRelease)
|
||||
assert.Equal(t, E.Left[int](err), res)
|
||||
}
|
||||
|
@@ -13,14 +13,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
// Package reader implements a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
package reader
|
||||
package readerioeither
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
R "github.com/IBM/fp-go/reader"
|
||||
G "github.com/IBM/fp-go/context/readerioeither/generic"
|
||||
)
|
||||
|
||||
// Reader is a specialization of the Reader monad assuming a golang context as the context of the monad
|
||||
type Reader[A any] R.Reader[context.Context, A]
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[A any](lock ReaderIOEither[context.CancelFunc]) func(fa ReaderIOEither[A]) ReaderIOEither[A] {
|
||||
return G.WithLock[ReaderIOEither[A]](lock)
|
||||
}
|
@@ -22,6 +22,8 @@ package either
|
||||
import (
|
||||
E "github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
@@ -92,11 +94,11 @@ func MonadChainTo[E, A, B any](ma Either[E, A], mb Either[E, 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[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 Chain(F.Flow2(f, from))
|
||||
}
|
||||
@@ -118,16 +120,15 @@ func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
|
||||
return MonadChain(mma, F.Identity[Either[E, A]])
|
||||
}
|
||||
|
||||
func TryCatch[FA ~func() (A, error), FE func(error) E, E, A any](f FA, onThrow FE) Either[E, A] {
|
||||
val, err := f()
|
||||
func TryCatch[FE func(error) E, E, A any](val A, err error, onThrow FE) Either[E, A] {
|
||||
if err != nil {
|
||||
return F.Pipe2(err, onThrow, Left[A, E])
|
||||
}
|
||||
return F.Pipe1(val, Right[E, A])
|
||||
}
|
||||
|
||||
func TryCatchError[F ~func() (A, error), A any](f F) Either[error, A] {
|
||||
return TryCatch(f, E.IdentityError)
|
||||
func TryCatchError[A any](val A, err error) Either[error, A] {
|
||||
return TryCatch(val, err, E.IdentityError)
|
||||
}
|
||||
|
||||
func Sequence2[E, T1, T2, R any](f func(T1, T2) Either[E, R]) func(Either[E, T1], Either[E, T2]) Either[E, R] {
|
||||
@@ -142,7 +143,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])
|
||||
}
|
||||
|
||||
@@ -152,9 +153,7 @@ func ToOption[E, A any](ma Either[E, A]) O.Option[A] {
|
||||
|
||||
func FromError[A any](f func(a A) error) func(A) Either[error, A] {
|
||||
return func(a A) Either[error, A] {
|
||||
return TryCatchError(func() (A, error) {
|
||||
return a, f(a)
|
||||
})
|
||||
return TryCatchError(a, f(a))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -197,11 +196,11 @@ func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B {
|
||||
)
|
||||
}
|
||||
|
||||
func AltW[E, E1, A any](that func() Either[E1, A]) func(Either[E, A]) Either[E1, A] {
|
||||
func AltW[E, E1, A any](that L.Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A] {
|
||||
return Fold(F.Ignore1of1[E](that), Right[E1, A])
|
||||
}
|
||||
|
||||
func Alt[E, A any](that func() Either[E, A]) func(Either[E, A]) Either[E, A] {
|
||||
func Alt[E, A any](that L.Lazy[Either[E, A]]) func(Either[E, A]) Either[E, A] {
|
||||
return AltW[E](that)
|
||||
}
|
||||
|
||||
@@ -245,3 +244,15 @@ func MonadSequence3[E, T1, T2, T3, R any](e1 Either[E, T1], e2 Either[E, T2], e3
|
||||
func Swap[E, A any](val Either[E, A]) Either[A, E] {
|
||||
return MonadFold(val, Right[A, E], Left[E, A])
|
||||
}
|
||||
|
||||
func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
|
||||
return FC.MonadFlap(MonadMap[E, func(A) B, B], fab, a)
|
||||
}
|
||||
|
||||
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
|
||||
return F.Bind2nd(MonadFlap[E, B, A], a)
|
||||
}
|
||||
|
||||
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
|
||||
return MonadFold(fa, F.Ignore1of1[E](that), Of[E, A])
|
||||
}
|
||||
|
@@ -112,6 +112,6 @@ func TestChainOptionK(t *testing.T) {
|
||||
}
|
||||
|
||||
func TestFromOption(t *testing.T) {
|
||||
assert.Equal(t, Left[int]("none"), FromOption[string, int](F.Constant("none"))(O.None[int]()))
|
||||
assert.Equal(t, Right[string](1), FromOption[string, int](F.Constant("none"))(O.Some(1)))
|
||||
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
||||
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
||||
}
|
||||
|
@@ -27,12 +27,10 @@ import (
|
||||
var (
|
||||
// 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
|
||||
// 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)
|
||||
)
|
||||
|
||||
func command(name string, args []string, in []byte) E.Either[error, exec.CommandOutput] {
|
||||
return E.TryCatchError(func() (exec.CommandOutput, error) {
|
||||
return GE.Exec(context.Background(), name, args, in)
|
||||
})
|
||||
return E.TryCatchError(GE.Exec(context.Background(), name, args, in))
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:15.6356542 +0200 CEST m=+0.009418901
|
||||
// 2023-10-23 08:30:40.410373 +0200 CEST m=+0.010337601
|
||||
|
||||
package either
|
||||
|
||||
@@ -13,9 +13,7 @@ import (
|
||||
// The inverse function is [Uneitherize0]
|
||||
func Eitherize0[F ~func() (R, error), R any](f F) func() Either[error, R] {
|
||||
return func() Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f()
|
||||
})
|
||||
return TryCatchError(f())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,9 +29,7 @@ func Uneitherize0[F ~func() Either[error, R], R any](f F) func() (R, error) {
|
||||
// The inverse function is [Uneitherize1]
|
||||
func Eitherize1[F ~func(T0) (R, error), T0, R any](f F) func(T0) Either[error, R] {
|
||||
return func(t0 T0) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0)
|
||||
})
|
||||
return TryCatchError(f(t0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,9 +72,7 @@ func TraverseTuple1[F1 ~func(A1) Either[E, T1], E, A1, T1 any](f1 F1) func(T.Tup
|
||||
// The inverse function is [Uneitherize2]
|
||||
func Eitherize2[F ~func(T0, T1) (R, error), T0, T1, R any](f F) func(T0, T1) Either[error, R] {
|
||||
return func(t0 T0, t1 T1) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1)
|
||||
})
|
||||
return TryCatchError(f(t0, t1))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +120,7 @@ func TraverseTuple2[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], E, A
|
||||
// The inverse function is [Uneitherize3]
|
||||
func Eitherize3[F ~func(T0, T1, T2) (R, error), T0, T1, T2, R any](f F) func(T0, T1, T2) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,9 +173,7 @@ func TraverseTuple3[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize4]
|
||||
func Eitherize4[F ~func(T0, T1, T2, T3) (R, error), T0, T1, T2, T3, R any](f F) func(T0, T1, T2, T3) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,9 +231,7 @@ func TraverseTuple4[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize5]
|
||||
func Eitherize5[F ~func(T0, T1, T2, T3, T4) (R, error), T0, T1, T2, T3, T4, R any](f F) func(T0, T1, T2, T3, T4) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -306,9 +294,7 @@ func TraverseTuple5[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize6]
|
||||
func Eitherize6[F ~func(T0, T1, T2, T3, T4, T5) (R, error), T0, T1, T2, T3, T4, T5, R any](f F) func(T0, T1, T2, T3, T4, T5) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4, t5)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4, t5))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -376,9 +362,7 @@ func TraverseTuple6[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize7]
|
||||
func Eitherize7[F ~func(T0, T1, T2, T3, T4, T5, T6) (R, error), T0, T1, T2, T3, T4, T5, T6, R any](f F) func(T0, T1, T2, T3, T4, T5, T6) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4, t5, t6)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,9 +435,7 @@ func TraverseTuple7[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize8]
|
||||
func Eitherize8[F ~func(T0, T1, T2, T3, T4, T5, T6, T7) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4, t5, t6, t7)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -531,9 +513,7 @@ func TraverseTuple8[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize9]
|
||||
func Eitherize9[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -616,9 +596,7 @@ func TraverseTuple9[F1 ~func(A1) Either[E, T1], F2 ~func(A2) Either[E, T2], F3 ~
|
||||
// The inverse function is [Uneitherize10]
|
||||
func Eitherize10[F ~func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) (R, error), T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, R any](f F) func(T0, T1, T2, T3, T4, T5, T6, T7, T8, T9) Either[error, R] {
|
||||
return func(t0 T0, t1 T1, t2 T2, t3 T3, t4 T4, t5 T5, t6 T6, t7 T7, t8 T8, t9 T9) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9)
|
||||
})
|
||||
return TryCatchError(f(t0, t1, t2, t3, t4, t5, t6, t7, t8, t9))
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -35,17 +35,13 @@ var (
|
||||
func bodyRequest(method string) func(string) func([]byte) E.Either[error, *http.Request] {
|
||||
return func(url string) func([]byte) E.Either[error, *http.Request] {
|
||||
return func(body []byte) E.Either[error, *http.Request] {
|
||||
return E.TryCatchError(func() (*http.Request, error) {
|
||||
return http.NewRequest(method, url, bytes.NewReader(body))
|
||||
})
|
||||
return E.TryCatchError(http.NewRequest(method, url, bytes.NewReader(body)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func noBodyRequest(method string) func(string) E.Either[error, *http.Request] {
|
||||
return func(url string) E.Either[error, *http.Request] {
|
||||
return E.TryCatchError(func() (*http.Request, error) {
|
||||
return http.NewRequest(method, url, nil)
|
||||
})
|
||||
return E.TryCatchError(http.NewRequest(method, url, nil))
|
||||
}
|
||||
}
|
||||
|
40
either/monoid.go
Normal file
40
either/monoid.go
Normal file
@@ -0,0 +1,40 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package either
|
||||
|
||||
import (
|
||||
L "github.com/IBM/fp-go/lazy"
|
||||
M "github.com/IBM/fp-go/monoid"
|
||||
)
|
||||
|
||||
// AlternativeMonoid is the alternative [Monoid] for an [Either]
|
||||
func AlternativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] {
|
||||
return M.AlternativeMonoid(
|
||||
Of[E, A],
|
||||
MonadMap[E, A, func(A) A],
|
||||
MonadAp[A, E, A],
|
||||
MonadAlt[E, A],
|
||||
m,
|
||||
)
|
||||
}
|
||||
|
||||
// AltMonoid is the alternative [Monoid] for an [Either]
|
||||
func AltMonoid[E, A any](zero L.Lazy[Either[E, A]]) M.Monoid[Either[E, A]] {
|
||||
return M.AltMonoid(
|
||||
zero,
|
||||
MonadAlt[E, A],
|
||||
)
|
||||
}
|
@@ -25,20 +25,14 @@ import (
|
||||
|
||||
func TestWithResource(t *testing.T) {
|
||||
onCreate := func() Either[error, *os.File] {
|
||||
return TryCatchError(func() (*os.File, error) {
|
||||
return os.CreateTemp("", "*")
|
||||
})
|
||||
return TryCatchError(os.CreateTemp("", "*"))
|
||||
}
|
||||
onDelete := F.Flow2(
|
||||
func(f *os.File) Either[error, string] {
|
||||
return TryCatchError(func() (string, error) {
|
||||
return f.Name(), f.Close()
|
||||
})
|
||||
return TryCatchError(f.Name(), f.Close())
|
||||
},
|
||||
Chain(func(name string) Either[error, any] {
|
||||
return TryCatchError(func() (any, error) {
|
||||
return name, os.Remove(name)
|
||||
})
|
||||
return TryCatchError(any(name), os.Remove(name))
|
||||
}),
|
||||
)
|
||||
|
||||
|
@@ -13,17 +13,15 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package file
|
||||
package either
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
// onClose closes a closeable resource
|
||||
func onClose[R io.Closer](r R) IOE.IOEither[error, R] {
|
||||
return IOE.TryCatchError(func() (R, error) {
|
||||
return r, r.Close()
|
||||
})
|
||||
// AltSemigroup is the alternative [Semigroup] for an [Either]
|
||||
func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]] {
|
||||
return S.AltSemigroup(
|
||||
MonadAlt[E, A],
|
||||
)
|
||||
}
|
@@ -17,80 +17,60 @@ package either
|
||||
|
||||
func Variadic0[V, R any](f func([]V) (R, error)) func(...V) Either[error, R] {
|
||||
return func(v ...V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(v)
|
||||
})
|
||||
return TryCatchError(f(v))
|
||||
}
|
||||
}
|
||||
|
||||
func Variadic1[T1, V, R any](f func(T1, []V) (R, error)) func(T1, ...V) Either[error, R] {
|
||||
return func(t1 T1, v ...V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, v)
|
||||
})
|
||||
return TryCatchError(f(t1, v))
|
||||
}
|
||||
}
|
||||
|
||||
func Variadic2[T1, T2, V, R any](f func(T1, T2, []V) (R, error)) func(T1, T2, ...V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, v ...V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, v)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, v))
|
||||
}
|
||||
}
|
||||
|
||||
func Variadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, []V) (R, error)) func(T1, T2, T3, ...V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, t3 T3, v ...V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, t3, v)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, t3, v))
|
||||
}
|
||||
}
|
||||
|
||||
func Variadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, []V) (R, error)) func(T1, T2, T3, T4, ...V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, t3 T3, t4 T4, v ...V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, t3, t4, v)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, t3, t4, v))
|
||||
}
|
||||
}
|
||||
|
||||
func Unvariadic0[V, R any](f func(...V) (R, error)) func([]V) Either[error, R] {
|
||||
return func(v []V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(v...)
|
||||
})
|
||||
return TryCatchError(f(v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Unvariadic1[T1, V, R any](f func(T1, ...V) (R, error)) func(T1, []V) Either[error, R] {
|
||||
return func(t1 T1, v []V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, v...)
|
||||
})
|
||||
return TryCatchError(f(t1, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Unvariadic2[T1, T2, V, R any](f func(T1, T2, ...V) (R, error)) func(T1, T2, []V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, v []V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, v...)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Unvariadic3[T1, T2, T3, V, R any](f func(T1, T2, T3, ...V) (R, error)) func(T1, T2, T3, []V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, t3 T3, v []V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, t3, v...)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, t3, v...))
|
||||
}
|
||||
}
|
||||
|
||||
func Unvariadic4[T1, T2, T3, T4, V, R any](f func(T1, T2, T3, T4, ...V) (R, error)) func(T1, T2, T3, T4, []V) Either[error, R] {
|
||||
return func(t1 T1, t2 T2, t3 T3, t4 T4, v []V) Either[error, R] {
|
||||
return TryCatchError(func() (R, error) {
|
||||
return f(t1, t2, t3, t4, v...)
|
||||
})
|
||||
return TryCatchError(f(t1, t2, t3, t4, v...))
|
||||
}
|
||||
}
|
||||
|
@@ -20,11 +20,14 @@ import (
|
||||
)
|
||||
|
||||
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]
|
||||
)
|
||||
|
||||
var (
|
||||
// StdOut returns the field of a [CommandOutput] representing `stdout`
|
||||
StdOut = T.First[[]byte, []byte]
|
||||
// StdErr returns the field of a [CommandOutput] representing `stderr`
|
||||
StdErr = T.Second[[]byte, []byte]
|
||||
)
|
||||
|
@@ -15,9 +15,11 @@
|
||||
|
||||
package file
|
||||
|
||||
import "os"
|
||||
import "path/filepath"
|
||||
|
||||
// GetName is the getter for the `Name` property of [os.File]
|
||||
func GetName(f *os.File) string {
|
||||
return f.Name()
|
||||
// Join appends a filename to a root path
|
||||
func Join(name string) func(root string) string {
|
||||
return func(root string) string {
|
||||
return filepath.Join(root, name)
|
||||
}
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:23.4226437 +0200 CEST m=+0.011841001
|
||||
// 2023-10-23 08:30:44.6474482 +0200 CEST m=+0.150851901
|
||||
|
||||
package function
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:17.0002767 +0200 CEST m=+0.008233101
|
||||
// 2023-10-23 08:30:41.7972101 +0200 CEST m=+0.008029101
|
||||
|
||||
package function
|
||||
|
||||
|
@@ -57,7 +57,7 @@ var (
|
||||
GetHeader,
|
||||
R.Lookup[H.Header](HeaderContentType),
|
||||
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),
|
||||
)))
|
||||
)
|
||||
@@ -68,10 +68,8 @@ const (
|
||||
|
||||
// ParseMediaType parses a media type into a tuple
|
||||
func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] {
|
||||
return E.TryCatchError(func() (ParsedMediaType, error) {
|
||||
m, p, err := mime.ParseMediaType(mediaType)
|
||||
return T.MakeTuple2(m, p), err
|
||||
})
|
||||
m, p, err := mime.ParseMediaType(mediaType)
|
||||
return E.TryCatchError(T.MakeTuple2(m, p), err)
|
||||
}
|
||||
|
||||
func GetHeader(resp *H.Response) H.Header {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:24.9409324 +0200 CEST m=+0.008573601
|
||||
// 2023-10-23 08:30:50.5492271 +0200 CEST m=+0.023274501
|
||||
|
||||
package identity
|
||||
|
||||
|
@@ -18,6 +18,7 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
)
|
||||
|
||||
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 {
|
||||
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
|
||||
}
|
||||
|
||||
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
|
||||
return FC.MonadFlap(MonadMap[func(GAB) B, GAB, B], fab, a)
|
||||
}
|
||||
|
||||
func Flap[GAB ~func(A) B, A, B any](a A) func(GAB) B {
|
||||
return F.Bind2nd(MonadFlap[GAB, A, B], a)
|
||||
}
|
||||
|
@@ -63,3 +63,11 @@ func MonadChainFirst[A, B any](fa A, f func(A) B) A {
|
||||
func ChainFirst[A, B any](f func(A) B) func(A) A {
|
||||
return G.ChainFirst(f)
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab func(A) B, a A) B {
|
||||
return G.MonadFlap[func(A) B](fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func(func(A) B) B {
|
||||
return G.Flap[func(A) B](a)
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:26.2499883 +0200 CEST m=+0.007601301
|
||||
// 2023-10-23 08:30:54.1909432 +0200 CEST m=+0.014252201
|
||||
|
||||
package apply
|
||||
|
||||
|
@@ -46,9 +46,7 @@ func MakeReader(ctx context.Context, rdr io.Reader) io.Reader {
|
||||
|
||||
// ReadAll reads the content of a reader and allows it to be canceled
|
||||
func ReadAll(ctx context.Context, rdr io.Reader) E.Either[error, []byte] {
|
||||
return E.TryCatchError(func() ([]byte, error) {
|
||||
var buffer bytes.Buffer
|
||||
_, err := io.Copy(&buffer, MakeReader(ctx, rdr))
|
||||
return buffer.Bytes(), err
|
||||
})
|
||||
var buffer bytes.Buffer
|
||||
_, err := io.Copy(&buffer, MakeReader(ctx, rdr))
|
||||
return E.TryCatchError(buffer.Bytes(), err)
|
||||
}
|
||||
|
@@ -22,8 +22,8 @@ import (
|
||||
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 {
|
||||
return F.Flow2(ET.FromOption[E, A](onNone), fromEither)
|
||||
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[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 {
|
||||
@@ -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,
|
||||
onNone func() E) func(f func(A) O.Option[B]) func(A) HKTEB {
|
||||
// helper
|
||||
@@ -65,7 +65,7 @@ func ChainOptionK[A, E, B, HKTEA, HKTEB any](
|
||||
fromEither func(ET.Either[E, B]) HKTEB,
|
||||
onNone func() E,
|
||||
) 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](
|
||||
|
37
internal/functor/flap.go
Normal file
37
internal/functor/flap.go
Normal file
@@ -0,0 +1,37 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package functor
|
||||
|
||||
func MonadFlap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||
fmap func(HKTFAB, func(FAB) B) HKTB,
|
||||
|
||||
fab HKTFAB,
|
||||
a A,
|
||||
) HKTB {
|
||||
return fmap(fab, func(f FAB) B {
|
||||
return f(a)
|
||||
})
|
||||
}
|
||||
|
||||
func Flap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||
fmap func(HKTFAB, func(FAB) B) HKTB,
|
||||
|
||||
a A,
|
||||
) func(HKTFAB) HKTB {
|
||||
return func(fab HKTFAB) HKTB {
|
||||
return MonadFlap(fmap, fab, a)
|
||||
}
|
||||
}
|
30
io/bracket.go
Normal file
30
io/bracket.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package io
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[A, B, ANY any](
|
||||
acquire IO[A],
|
||||
use func(A) IO[B],
|
||||
release func(A, B) IO[ANY],
|
||||
) IO[B] {
|
||||
return G.Bracket(acquire, use, release)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
|
||||
// 2023-10-23 08:30:56.7105551 +0200 CEST m=+0.011255201
|
||||
|
||||
package io
|
||||
|
||||
|
44
io/generic/bracket.go
Normal file
44
io/generic/bracket.go
Normal file
@@ -0,0 +1,44 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/internal/bracket"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
GA ~func() A,
|
||||
GB ~func() B,
|
||||
GANY ~func() ANY,
|
||||
A, B, ANY any](
|
||||
|
||||
acquire GA,
|
||||
use func(A) GB,
|
||||
release func(A, B) GANY,
|
||||
) GB {
|
||||
return G.Bracket[GA, GB, GANY, B, A, B](
|
||||
Of[GB, B],
|
||||
MonadChain[GA, GB, A, B],
|
||||
MonadChain[GB, GB, B, B],
|
||||
MonadChain[GANY, GB, ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:27.9813739 +0200 CEST m=+0.011088001
|
||||
// 2023-10-23 08:30:56.7105551 +0200 CEST m=+0.011255201
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
@@ -20,6 +20,7 @@ import (
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
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()()
|
||||
})
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
30
io/generic/sync.go
Normal file
30
io/generic/sync.go
Normal file
@@ -0,0 +1,30 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[GA ~func() A, A any](lock func() context.CancelFunc) func(fa GA) GA {
|
||||
return func(fa GA) GA {
|
||||
return func() A {
|
||||
defer lock()()
|
||||
return fa()
|
||||
}
|
||||
}
|
||||
}
|
10
io/io.go
10
io/io.go
@@ -84,7 +84,7 @@ func Flatten[A any](mma IO[IO[A]]) IO[A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
// 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] {
|
||||
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] {
|
||||
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)
|
||||
}
|
||||
|
27
io/sync.go
Normal file
27
io/sync.go
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package io
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
G "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided [IO] operation in the scope of a lock
|
||||
func WithLock[A any](lock IO[context.CancelFunc]) func(fa IO[A]) IO[A] {
|
||||
return G.WithLock[IO[A]](lock)
|
||||
}
|
@@ -16,6 +16,7 @@
|
||||
package file
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
|
||||
IOE "github.com/IBM/fp-go/ioeither"
|
||||
@@ -45,3 +46,10 @@ func Remove(name string) IOE.IOEither[error, string] {
|
||||
return name, os.Remove(name)
|
||||
})
|
||||
}
|
||||
|
||||
// Close closes an object
|
||||
func Close[C io.Closer](c C) IOE.IOEither[error, any] {
|
||||
return IOE.TryCatchError(func() (any, error) {
|
||||
return c, c.Close()
|
||||
})
|
||||
}
|
||||
|
@@ -31,7 +31,7 @@ func onReadAll[R io.Reader](r R) IOE.IOEither[error, []byte] {
|
||||
func ReadAll[R io.ReadCloser](acquire IOE.IOEither[error, R]) IOE.IOEither[error, []byte] {
|
||||
return IOE.WithResource[[]byte](
|
||||
acquire,
|
||||
onClose[R])(
|
||||
Close[R])(
|
||||
onReadAll[R],
|
||||
)
|
||||
}
|
||||
|
@@ -18,7 +18,6 @@ package file
|
||||
import (
|
||||
"os"
|
||||
|
||||
FL "github.com/IBM/fp-go/file"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
IOF "github.com/IBM/fp-go/io/file"
|
||||
@@ -33,7 +32,7 @@ var (
|
||||
// destroy handler
|
||||
onReleaseTempFile = F.Flow4(
|
||||
IOF.Close[*os.File],
|
||||
IO.Map(FL.GetName),
|
||||
IO.Map((*os.File).Name),
|
||||
IOE.FromIO[error, string],
|
||||
IOE.Chain(Remove),
|
||||
)
|
||||
|
@@ -38,7 +38,7 @@ func TestWithTempFileOnClosedFile(t *testing.T) {
|
||||
return F.Pipe2(
|
||||
f,
|
||||
onWriteAll[*os.File]([]byte("Carsten")),
|
||||
IOE.ChainFirst(F.Constant1[[]byte](onClose(f))),
|
||||
IOE.ChainFirst(F.Constant1[[]byte](Close(f))),
|
||||
)
|
||||
})
|
||||
|
||||
|
@@ -36,7 +36,7 @@ func WriteAll[W io.WriteCloser](data []byte) func(acquire IOE.IOEither[error, W]
|
||||
return func(onCreate IOE.IOEither[error, W]) IOE.IOEither[error, []byte] {
|
||||
return IOE.WithResource[[]byte](
|
||||
onCreate,
|
||||
onClose[W])(
|
||||
Close[W])(
|
||||
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] {
|
||||
return IOE.WithResource[R](
|
||||
acquire,
|
||||
onClose[W])
|
||||
Close[W])
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
|
||||
// 2023-10-23 08:30:58.6457744 +0200 CEST m=+0.080336501
|
||||
|
||||
package ioeither
|
||||
|
||||
|
@@ -17,7 +17,7 @@ package generic
|
||||
|
||||
import (
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
G "github.com/IBM/fp-go/internal/file"
|
||||
G "github.com/IBM/fp-go/internal/bracket"
|
||||
I "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:29.4935658 +0200 CEST m=+0.015377401
|
||||
// 2023-10-23 08:30:58.6556525 +0200 CEST m=+0.090214601
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
@@ -19,12 +19,12 @@ import (
|
||||
"time"
|
||||
|
||||
ET "github.com/IBM/fp-go/either"
|
||||
"github.com/IBM/fp-go/errors"
|
||||
F "github.com/IBM/fp-go/function"
|
||||
C "github.com/IBM/fp-go/internal/chain"
|
||||
"github.com/IBM/fp-go/internal/eithert"
|
||||
FE "github.com/IBM/fp-go/internal/fromeither"
|
||||
FI "github.com/IBM/fp-go/internal/fromio"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
@@ -183,12 +183,15 @@ func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any]
|
||||
|
||||
func TryCatch[GA ~func() ET.Either[E, A], E, A any](f func() (A, error), onThrow func(error) E) GA {
|
||||
return MakeIO(func() ET.Either[E, A] {
|
||||
return ET.TryCatch(f, onThrow)
|
||||
a, err := f()
|
||||
return ET.TryCatch(a, err, onThrow)
|
||||
})
|
||||
}
|
||||
|
||||
func TryCatchError[GA ~func() ET.Either[error, A], A any](f func() (A, error)) GA {
|
||||
return TryCatch[GA](f, errors.IdentityError)
|
||||
return MakeIO(func() ET.Either[error, A] {
|
||||
return ET.TryCatchError(f())
|
||||
})
|
||||
}
|
||||
|
||||
// Memoize computes the value of the provided IO monad lazily but exactly once
|
||||
@@ -304,3 +307,11 @@ func MonadAlt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](first G
|
||||
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)
|
||||
}
|
||||
|
28
ioeither/generic/sync.go
Normal file
28
ioeither/generic/sync.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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"
|
||||
G "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[GA ~func() ET.Either[E, A], E, A any](lock func() context.CancelFunc) func(fa GA) GA {
|
||||
return G.WithLock[GA](lock)
|
||||
}
|
@@ -231,3 +231,11 @@ func MonadAlt[E, A any](first IOEither[E, A], second L.Lazy[IOEither[E, A]]) IOE
|
||||
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)
|
||||
}
|
||||
|
28
ioeither/sync.go
Normal file
28
ioeither/sync.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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 (
|
||||
"context"
|
||||
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
G "github.com/IBM/fp-go/ioeither/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[E, A any](lock IO.IO[context.CancelFunc]) func(fa IOEither[E, A]) IOEither[E, A] {
|
||||
return G.WithLock[IOEither[E, A]](lock)
|
||||
}
|
31
iooption/bracket.go
Normal file
31
iooption/bracket.go
Normal file
@@ -0,0 +1,31 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iooption
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/iooption/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[E, A, B, ANY any](
|
||||
acquire IOOption[A],
|
||||
use func(A) IOOption[B],
|
||||
release func(A, O.Option[B]) IOOption[ANY],
|
||||
) IOOption[B] {
|
||||
return G.Bracket(acquire, use, release)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:32.1514823 +0200 CEST m=+0.098931001
|
||||
// 2023-10-23 08:31:01.9227118 +0200 CEST m=+0.009977901
|
||||
|
||||
package iooption
|
||||
|
||||
|
46
iooption/generic/bracket.go
Normal file
46
iooption/generic/bracket.go
Normal file
@@ -0,0 +1,46 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
G "github.com/IBM/fp-go/internal/bracket"
|
||||
I "github.com/IBM/fp-go/io/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
|
||||
// whether the body action returns and error or not.
|
||||
func Bracket[
|
||||
GA ~func() O.Option[A],
|
||||
GB ~func() O.Option[B],
|
||||
GANY ~func() O.Option[ANY],
|
||||
A, B, ANY any](
|
||||
|
||||
acquire GA,
|
||||
use func(A) GB,
|
||||
release func(A, O.Option[B]) GANY,
|
||||
) GB {
|
||||
return G.Bracket[GA, GB, GANY, O.Option[B], A, B](
|
||||
I.Of[GB, O.Option[B]],
|
||||
MonadChain[GA, GB, A, B],
|
||||
I.MonadChain[GB, GB, O.Option[B], O.Option[B]],
|
||||
MonadChain[GANY, GB, ANY, B],
|
||||
|
||||
acquire,
|
||||
use,
|
||||
release,
|
||||
)
|
||||
}
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:32.1546277 +0200 CEST m=+0.102076401
|
||||
// 2023-10-23 08:31:01.9227118 +0200 CEST m=+0.009977901
|
||||
package generic
|
||||
|
||||
import (
|
||||
|
28
iooption/generic/sync.go
Normal file
28
iooption/generic/sync.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// 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"
|
||||
|
||||
G "github.com/IBM/fp-go/io/generic"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[GA ~func() O.Option[A], A any](lock func() context.CancelFunc) func(fa GA) GA {
|
||||
return G.WithLock[GA](lock)
|
||||
}
|
28
iooption/sync.go
Normal file
28
iooption/sync.go
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package iooption
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
IO "github.com/IBM/fp-go/io"
|
||||
G "github.com/IBM/fp-go/iooption/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[E, A any](lock IO.IO[context.CancelFunc]) func(fa IOOption[A]) IOOption[A] {
|
||||
return G.WithLock[IOOption[A]](lock)
|
||||
}
|
12
json/json.go
12
json/json.go
@@ -23,16 +23,12 @@ import (
|
||||
|
||||
// Unmarshal parses a JSON data structure from bytes
|
||||
func Unmarshal[A any](data []byte) E.Either[error, A] {
|
||||
return E.TryCatchError(func() (A, error) {
|
||||
var result A
|
||||
err := json.Unmarshal(data, &result)
|
||||
return result, err
|
||||
})
|
||||
var result A
|
||||
err := json.Unmarshal(data, &result)
|
||||
return E.TryCatchError(result, err)
|
||||
}
|
||||
|
||||
// Marshal converts a data structure to json
|
||||
func Marshal[A any](a A) E.Either[error, []byte] {
|
||||
return E.TryCatchError(func() ([]byte, error) {
|
||||
return json.Marshal(a)
|
||||
})
|
||||
return E.TryCatchError(json.Marshal(a))
|
||||
}
|
||||
|
@@ -19,13 +19,13 @@ import (
|
||||
S "github.com/IBM/fp-go/semigroup"
|
||||
)
|
||||
|
||||
func AlternativeMonoid[A, HKTA, HKTFA any](
|
||||
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, func() HKTA) HKTA,
|
||||
falt func(HKTA, LAZYHKTA) HKTA,
|
||||
|
||||
m Monoid[A],
|
||||
|
||||
@@ -45,9 +45,9 @@ func AlternativeMonoid[A, HKTA, HKTFA any](
|
||||
)
|
||||
}
|
||||
|
||||
func AltMonoid[HKTA any](
|
||||
fzero func() HKTA,
|
||||
falt func(HKTA, func() HKTA) HKTA,
|
||||
func AltMonoid[HKTA any, LAZYHKTA ~func() HKTA](
|
||||
fzero LAZYHKTA,
|
||||
falt func(HKTA, LAZYHKTA) HKTA,
|
||||
|
||||
) Monoid[HKTA] {
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:34.2077257 +0200 CEST m=+0.023541001
|
||||
// 2023-10-23 08:31:07.8687134 +0200 CEST m=+0.012222901
|
||||
|
||||
package option
|
||||
|
||||
|
@@ -51,3 +51,22 @@ func Monoid[A any]() func(S.Semigroup[A]) M.Monoid[Option[A]] {
|
||||
return M.MakeMonoid(sg(s).Concat, None[A]())
|
||||
}
|
||||
}
|
||||
|
||||
// AlternativeMonoid is the alternative [Monoid] for an [Option]
|
||||
func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] {
|
||||
return M.AlternativeMonoid(
|
||||
Of[A],
|
||||
MonadMap[A, func(A) A],
|
||||
MonadAp[A, A],
|
||||
MonadAlt[A],
|
||||
m,
|
||||
)
|
||||
}
|
||||
|
||||
// AltMonoid is the alternative [Monoid] for an [Option]
|
||||
func AltMonoid[A any]() M.Monoid[Option[A]] {
|
||||
return M.AltMonoid(
|
||||
None[A],
|
||||
MonadAlt[A],
|
||||
)
|
||||
}
|
||||
|
@@ -18,6 +18,7 @@ package option
|
||||
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
)
|
||||
|
||||
func fromPredicate[A any](a A, pred func(A) bool) Option[A] {
|
||||
@@ -115,6 +116,10 @@ func Flatten[A any](mma Option[Option[A]]) Option[A] {
|
||||
return MonadChain(mma, F.Identity[Option[A]])
|
||||
}
|
||||
|
||||
func MonadAlt[A any](fa Option[A], that func() Option[A]) Option[A] {
|
||||
return MonadFold(fa, that, Of[A])
|
||||
}
|
||||
|
||||
func Alt[A any](that func() Option[A]) func(Option[A]) Option[A] {
|
||||
return Fold(that, Of[A])
|
||||
}
|
||||
@@ -141,3 +146,11 @@ func Reduce[A, B any](f func(B, A) B, initial B) func(Option[A]) B {
|
||||
func Filter[A any](pred func(A) bool) func(Option[A]) Option[A] {
|
||||
return Fold(None[A], F.Ternary(pred, Of[A], F.Ignore1of1[A](None[A])))
|
||||
}
|
||||
|
||||
func MonadFlap[B, A any](fab Option[func(A) B], a A) Option[B] {
|
||||
return FC.MonadFlap(MonadMap[func(A) B, B], fab, a)
|
||||
}
|
||||
|
||||
func Flap[B, A any](a A) func(Option[func(A) B]) Option[B] {
|
||||
return F.Bind2nd(MonadFlap[B, A], a)
|
||||
}
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:36.1655251 +0200 CEST m=+0.010000501
|
||||
// 2023-10-23 08:31:13.0131834 +0200 CEST m=+0.010996501
|
||||
|
||||
package reader
|
||||
|
||||
|
@@ -1,6 +1,6 @@
|
||||
// Code generated by go generate; DO NOT EDIT.
|
||||
// This file was generated by robots at
|
||||
// 2023-09-12 13:44:36.166526 +0200 CEST m=+0.011001401
|
||||
// 2023-10-23 08:31:13.0131834 +0200 CEST m=+0.010996501
|
||||
package generic
|
||||
|
||||
// From0 converts a function with 1 parameters returning a [R] into a function with 0 parameters returning a [GRA]
|
||||
|
@@ -18,6 +18,7 @@ package generic
|
||||
import (
|
||||
F "github.com/IBM/fp-go/function"
|
||||
I "github.com/IBM/fp-go/identity/generic"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
T "github.com/IBM/fp-go/tuple"
|
||||
)
|
||||
|
||||
@@ -120,3 +121,11 @@ func Local[GA1 ~func(R1) A, GA2 ~func(R2) A, R2, R1, A any](f func(R2) R1) func(
|
||||
func Read[GA ~func(E) A, E, A any](e E) func(GA) A {
|
||||
return I.Ap[GA](e)
|
||||
}
|
||||
|
||||
func MonadFlap[GAB ~func(R) func(A) B, GB ~func(R) B, R, A, B any](fab GAB, a A) GB {
|
||||
return FC.MonadFlap(MonadMap[GAB, GB], fab, a)
|
||||
}
|
||||
|
||||
func Flap[GAB ~func(R) func(A) B, GB ~func(R) B, R, A, B any](a A) func(GAB) GB {
|
||||
return FC.Flap(MonadMap[GAB, GB], a)
|
||||
}
|
||||
|
@@ -105,3 +105,11 @@ func Local[R2, R1, A any](f func(R2) R1) func(Reader[R1, A]) Reader[R2, A] {
|
||||
func Read[E, A any](e E) func(Reader[E, A]) A {
|
||||
return G.Read[Reader[E, A]](e)
|
||||
}
|
||||
|
||||
func MonadFlap[R, A, B any](fab Reader[R, func(A) B], a A) Reader[R, B] {
|
||||
return G.MonadFlap[Reader[R, func(A) B], Reader[R, B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[R, A, B any](a A) func(Reader[R, func(A) B]) Reader[R, B] {
|
||||
return G.Flap[Reader[R, func(A) B], Reader[R, B]](a)
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ import (
|
||||
"github.com/IBM/fp-go/internal/eithert"
|
||||
FE "github.com/IBM/fp-go/internal/fromeither"
|
||||
FR "github.com/IBM/fp-go/internal/fromreader"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/readert"
|
||||
O "github.com/IBM/fp-go/option"
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
@@ -155,3 +156,11 @@ func Local[GA1 ~func(R1) ET.Either[E, A], GA2 ~func(R2) ET.Either[E, A], R2, R1,
|
||||
func Read[GA ~func(E) ET.Either[E1, A], E, E1, A any](e E) func(GA) ET.Either[E1, A] {
|
||||
return R.Read[GA](e)
|
||||
}
|
||||
|
||||
func MonadFlap[GEFAB ~func(E) ET.Either[L, func(A) B], GEB ~func(E) ET.Either[L, B], L, E, A, B any](fab GEFAB, a A) GEB {
|
||||
return FC.MonadFlap(MonadMap[GEFAB, GEB], fab, a)
|
||||
}
|
||||
|
||||
func Flap[GEFAB ~func(E) ET.Either[L, func(A) B], GEB ~func(E) ET.Either[L, B], L, E, A, B any](a A) func(GEFAB) GEB {
|
||||
return FC.Flap(MonadMap[GEFAB, GEB], a)
|
||||
}
|
||||
|
@@ -143,3 +143,11 @@ func Local[E, A, R2, R1 any](f func(R2) R1) func(ReaderEither[R1, E, A]) ReaderE
|
||||
func Read[E1, A, E any](e E) func(ReaderEither[E, E1, A]) ET.Either[E1, A] {
|
||||
return G.Read[ReaderEither[E, E1, A]](e)
|
||||
}
|
||||
|
||||
func MonadFlap[L, E, A, B any](fab ReaderEither[L, E, func(A) B], a A) ReaderEither[L, E, B] {
|
||||
return G.MonadFlap[ReaderEither[L, E, func(A) B], ReaderEither[L, E, B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[L, E, B, A any](a A) func(ReaderEither[L, E, func(A) B]) ReaderEither[L, E, B] {
|
||||
return G.Flap[ReaderEither[L, E, func(A) B], ReaderEither[L, E, B]](a)
|
||||
}
|
||||
|
@@ -25,58 +25,58 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
testError = fmt.Errorf("error")
|
||||
errFoo = fmt.Errorf("error")
|
||||
)
|
||||
|
||||
func TestSequenceT1(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, string](testError)
|
||||
e1 := Left[MyContext, string](errFoo)
|
||||
|
||||
res1 := SequenceT1(t1)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple1("s1")), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT1(e1)
|
||||
assert.Equal(t, E.Left[T.Tuple1[string]](testError), res2(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple1[string]](errFoo), res2(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT2(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, string](testError)
|
||||
e1 := Left[MyContext, string](errFoo)
|
||||
t2 := Of[MyContext, error](2)
|
||||
e2 := Left[MyContext, int](testError)
|
||||
e2 := Left[MyContext, int](errFoo)
|
||||
|
||||
res1 := SequenceT2(t1, t2)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple2("s1", 2)), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT2(e1, t2)
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](testError), res2(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](errFoo), res2(defaultContext))
|
||||
|
||||
res3 := SequenceT2(t1, e2)
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](testError), res3(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple2[string, int]](errFoo), res3(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT3(t *testing.T) {
|
||||
|
||||
t1 := Of[MyContext, error]("s1")
|
||||
e1 := Left[MyContext, string](testError)
|
||||
e1 := Left[MyContext, string](errFoo)
|
||||
t2 := Of[MyContext, error](2)
|
||||
e2 := Left[MyContext, int](testError)
|
||||
e2 := Left[MyContext, int](errFoo)
|
||||
t3 := Of[MyContext, error](true)
|
||||
e3 := Left[MyContext, bool](testError)
|
||||
e3 := Left[MyContext, bool](errFoo)
|
||||
|
||||
res1 := SequenceT3(t1, t2, t3)
|
||||
assert.Equal(t, E.Of[error](T.MakeTuple3("s1", 2, true)), res1(defaultContext))
|
||||
|
||||
res2 := SequenceT3(e1, t2, t3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res2(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](errFoo), res2(defaultContext))
|
||||
|
||||
res3 := SequenceT3(t1, e2, t3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res3(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](errFoo), res3(defaultContext))
|
||||
|
||||
res4 := SequenceT3(t1, t2, e3)
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](testError), res4(defaultContext))
|
||||
assert.Equal(t, E.Left[T.Tuple3[string, int, bool]](errFoo), res4(defaultContext))
|
||||
}
|
||||
|
||||
func TestSequenceT4(t *testing.T) {
|
||||
|
@@ -16,8 +16,12 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
FIO "github.com/IBM/fp-go/internal/fromio"
|
||||
FR "github.com/IBM/fp-go/internal/fromreader"
|
||||
FC "github.com/IBM/fp-go/internal/functor"
|
||||
"github.com/IBM/fp-go/internal/readert"
|
||||
IO "github.com/IBM/fp-go/io/generic"
|
||||
R "github.com/IBM/fp-go/reader/generic"
|
||||
@@ -84,11 +88,37 @@ func Asks[GA ~func(E) A, GEA ~func(E) GIOA, GIOA ~func() A, E, A any](r GA) GEA
|
||||
}
|
||||
|
||||
func MonadChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GIOB) GEB {
|
||||
return MonadChain(ma, F.Flow2(f, FromIO[GEB]))
|
||||
return FIO.MonadChainIOK(
|
||||
MonadChain[GEA, GEB],
|
||||
FromIO[GEB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEB {
|
||||
return F.Bind2nd(MonadChainIOK[GEA, GEB, GIOA, GIOB, E, A, B], f)
|
||||
return FIO.ChainIOK(
|
||||
MonadChain[GEA, GEB],
|
||||
FromIO[GEB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
func MonadChainFirstIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GIOB) GEA {
|
||||
return FIO.MonadChainFirstIOK(
|
||||
MonadChain[GEA, GEA],
|
||||
MonadMap[GEB, GEA],
|
||||
FromIO[GEB],
|
||||
ma, f,
|
||||
)
|
||||
}
|
||||
|
||||
func ChainFirstIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEA {
|
||||
return FIO.ChainFirstIOK(
|
||||
MonadChain[GEA, GEA],
|
||||
MonadMap[GEB, GEA],
|
||||
FromIO[GEB],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// Defer creates an IO by creating a brand new IO via a generator function, each time
|
||||
@@ -99,3 +129,38 @@ func Defer[GEA ~func(E) GA, GA ~func() A, E, A any](gen func() GEA) GEA {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Memoize computes the value of the provided reader 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[GEA ~func(E) GA, GA ~func() A, E, A any](rdr GEA) GEA {
|
||||
// synchronization primitives
|
||||
var once sync.Once
|
||||
var result A
|
||||
// callback
|
||||
gen := func(e E) func() {
|
||||
return func() {
|
||||
result = rdr(e)()
|
||||
}
|
||||
}
|
||||
// returns our memoized wrapper
|
||||
return func(e E) GA {
|
||||
io := gen(e)
|
||||
return func() A {
|
||||
once.Do(io)
|
||||
return result
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func Flatten[GEA ~func(R) GIOA, GGEA ~func(R) GIOEA, GIOA ~func() A, GIOEA ~func() GEA, R, A any](mma GGEA) GEA {
|
||||
return MonadChain(mma, F.Identity[GEA])
|
||||
}
|
||||
|
||||
func MonadFlap[GEFAB ~func(E) GIOFAB, GEB ~func(E) GIOB, GIOFAB ~func() func(A) B, GIOB ~func() B, E, A, B any](fab GEFAB, a A) GEB {
|
||||
return FC.MonadFlap(MonadMap[GEFAB, GEB], fab, a)
|
||||
}
|
||||
|
||||
func Flap[GEFAB ~func(E) GIOFAB, GEB ~func(E) GIOB, GIOFAB ~func() func(A) B, GIOB ~func() B, E, A, B any](a A) func(GEFAB) GEB {
|
||||
return FC.Flap(MonadMap[GEFAB, GEB], a)
|
||||
}
|
||||
|
34
readerio/generic/sync.go
Normal file
34
readerio/generic/sync.go
Normal file
@@ -0,0 +1,34 @@
|
||||
// Copyright (c) 2023 IBM Corp.
|
||||
// All rights reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package generic
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
F "github.com/IBM/fp-go/function"
|
||||
G "github.com/IBM/fp-go/io/generic"
|
||||
)
|
||||
|
||||
// WithLock executes the provided IO operation in the scope of a lock
|
||||
func WithLock[GEA ~func(R) GIOA, GIOA ~func() A, R, A any](lock func() context.CancelFunc) func(fa GEA) GEA {
|
||||
l := G.WithLock[GIOA](lock)
|
||||
return func(fa GEA) GEA {
|
||||
return F.Flow2(
|
||||
fa,
|
||||
l,
|
||||
)
|
||||
}
|
||||
}
|
@@ -23,6 +23,7 @@ import (
|
||||
|
||||
type ReaderIO[E, A any] R.Reader[E, IO.IO[A]]
|
||||
|
||||
// FromIO converts an [IO.IO] to a [ReaderIO]
|
||||
func FromIO[E, A any](t IO.IO[A]) ReaderIO[E, A] {
|
||||
return G.FromIO[ReaderIO[E, A]](t)
|
||||
}
|
||||
@@ -75,3 +76,22 @@ func ChainIOK[E, A, B any](f func(A) IO.IO[B]) func(ReaderIO[E, A]) ReaderIO[E,
|
||||
func Defer[E, A any](gen func() ReaderIO[E, A]) ReaderIO[E, A] {
|
||||
return G.Defer[ReaderIO[E, 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[E, A any](rdr ReaderIO[E, A]) ReaderIO[E, A] {
|
||||
return G.Memoize[ReaderIO[E, A]](rdr)
|
||||
}
|
||||
|
||||
func Flatten[E, A any](mma ReaderIO[E, ReaderIO[E, A]]) ReaderIO[E, A] {
|
||||
return G.Flatten[ReaderIO[E, A], ReaderIO[E, ReaderIO[E, A]]](mma)
|
||||
}
|
||||
|
||||
func MonadFlap[E, A, B any](fab ReaderIO[E, func(A) B], a A) ReaderIO[E, B] {
|
||||
return G.MonadFlap[ReaderIO[E, func(A) B], ReaderIO[E, B]](fab, a)
|
||||
}
|
||||
|
||||
func Flap[E, A, B any](a A) func(ReaderIO[E, func(A) B]) ReaderIO[E, B] {
|
||||
return G.Flap[ReaderIO[E, func(A) B], ReaderIO[E, B]](a)
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user