mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-28 19:49:07 +02:00
Compare commits
29 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
0afedbd7fe | ||
|
3f1bde219a | ||
|
6f91e91eb9 | ||
|
9f6b6d4968 | ||
|
79652d8474 | ||
|
a774d63e66 | ||
|
d86cf55a3d | ||
|
8150ae2a68 | ||
|
7daf65effc | ||
|
909f7c3bce | ||
|
5f0c644c6d | ||
|
9b3d9c6930 | ||
|
59381c1e50 | ||
|
358573cc20 | ||
|
e166806d1b | ||
|
02ec50c91d | ||
|
9e04974d0e | ||
|
2f99ca471a | ||
|
3e09a19d68 | ||
|
839ef47054 | ||
|
144b27233b | ||
|
668eb85aea | ||
|
b077fed094 | ||
|
7d3759619c | ||
|
c73467caf5 | ||
|
ca606767f3 | ||
|
fb82af9a69 | ||
|
57ad8c6466 | ||
|
5a9f405362 |
4
.github/workflows/build.yml
vendored
4
.github/workflows/build.yml
vendored
@@ -26,7 +26,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
go-version: [ '1.20.x', '1.21.x']
|
go-version: [ '1.20.x', '1.21.x', '1.22.x']
|
||||||
steps:
|
steps:
|
||||||
# full checkout for semantic-release
|
# full checkout for semantic-release
|
||||||
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
|
||||||
@@ -60,7 +60,7 @@ jobs:
|
|||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
- name: Set up Node.js ${{ env.NODE_VERSION }}
|
||||||
uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1
|
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
|
||||||
with:
|
with:
|
||||||
node-version: ${{ env.NODE_VERSION }}
|
node-version: ${{ env.NODE_VERSION }}
|
||||||
|
|
||||||
|
@@ -58,7 +58,7 @@ func MapWithIndex[A, B any](f func(int, A) B) func([]A) []B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Map[A, B any](f func(a A) B) func([]A) []B {
|
func Map[A, B any](f func(a A) B) func([]A) []B {
|
||||||
return F.Bind2nd(MonadMap[A, B], f)
|
return G.Map[[]A, []B, A, B](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
func MapRef[A, B any](f func(a *A) B) func([]A) []B {
|
||||||
|
66
array/bind.go
Normal file
66
array/bind.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) []S {
|
||||||
|
return G.Do[[]S, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) []T,
|
||||||
|
) func([]S1) []S2 {
|
||||||
|
return G.Bind[[]S1, []S2, []T, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func([]S1) []S2 {
|
||||||
|
return G.Let[[]S1, []S2, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func([]S1) []S2 {
|
||||||
|
return G.LetTo[[]S1, []S2, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func([]T) []S1 {
|
||||||
|
return G.BindTo[[]S1, []T, S1, T](setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa []T,
|
||||||
|
) func([]S1) []S2 {
|
||||||
|
return G.ApS[[]S1, []S2, []T, S1, S2, T](setter, fa)
|
||||||
|
}
|
56
array/bind_test.go
Normal file
56
array/bind_test.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) []string {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) []string {
|
||||||
|
return Of("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res, Of("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of("John")),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res, Of("John Doe"))
|
||||||
|
}
|
@@ -147,7 +147,7 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
|
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
|
||||||
return F.Bind2nd(MonadMap[GA, GB, A, B], f)
|
return array.Map[GA, GB](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
|
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(int, A) B) GB {
|
||||||
@@ -344,7 +344,7 @@ func MonadFlap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](fab GFAB, a A) GB
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Flap[FAB ~func(A) B, GFAB ~[]FAB, GB ~[]B, A, B any](a A) func(GFAB) GB {
|
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)
|
return FC.Flap(Map[GFAB, GB], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
|
func Prepend[ENDO ~func(AS) AS, AS []A, A any](head A) ENDO {
|
||||||
|
89
array/generic/bind.go
Normal file
89
array/generic/bind.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// 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 (
|
||||||
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~[]S, S any](
|
||||||
|
empty S,
|
||||||
|
) GS {
|
||||||
|
return Of[GS](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GS1, GS2, S1, S2],
|
||||||
|
Map[GT, GS2, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~[]S1, GS2 ~[]S2, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~[]S1, GS2 ~[]S2, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~[]S1, GT ~[]T, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GS2, []func(T) S2, GT, S2, T],
|
||||||
|
Map[GS1, []func(T) S2, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
43
array/generic/monad.go
Normal file
43
array/generic/monad.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2024 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
)
|
||||||
|
|
||||||
|
type arrayMonad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B] struct{}
|
||||||
|
|
||||||
|
func (o *arrayMonad[A, B, GA, GB, GAB]) Of(a A) GA {
|
||||||
|
return Of[GA, A](a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *arrayMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
|
||||||
|
return Map[GA, GB, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *arrayMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
|
||||||
|
return Chain[GA, GB, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *arrayMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
|
||||||
|
return Ap[GB, GAB, GA, B, A](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monad implements the monadic operations for an array
|
||||||
|
func Monad[A, B any, GA ~[]A, GB ~[]B, GAB ~[]func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
|
||||||
|
return &arrayMonad[A, B, GA, GB, GAB]{}
|
||||||
|
}
|
26
array/monad.go
Normal file
26
array/monad.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package array
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/array/generic"
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Monad returns the monadic operations for an array
|
||||||
|
func Monad[A, B any]() monad.Monad[A, B, []A, []B, []func(A) B] {
|
||||||
|
return G.Monad[A, B, []A, []B, []func(A) B]()
|
||||||
|
}
|
@@ -44,11 +44,11 @@ func From[A any](first A, data ...A) NonEmptyArray[A] {
|
|||||||
return buffer
|
return buffer
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsEmpty[A any](as NonEmptyArray[A]) bool {
|
func IsEmpty[A any](_ NonEmptyArray[A]) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
func IsNonEmpty[A any](as NonEmptyArray[A]) bool {
|
func IsNonEmpty[A any](_ NonEmptyArray[A]) bool {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
74
array/testing/laws.go
Normal file
74
array/testing/laws.go
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
RA "github.com/IBM/fp-go/array"
|
||||||
|
EQ "github.com/IBM/fp-go/eq"
|
||||||
|
L "github.com/IBM/fp-go/internal/monad/testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssertLaws asserts the apply monad laws for the array monad
|
||||||
|
func AssertLaws[A, B, C any](t *testing.T,
|
||||||
|
eqa EQ.Eq[A],
|
||||||
|
eqb EQ.Eq[B],
|
||||||
|
eqc EQ.Eq[C],
|
||||||
|
|
||||||
|
ab func(A) B,
|
||||||
|
bc func(B) C,
|
||||||
|
) func(a A) bool {
|
||||||
|
|
||||||
|
return L.AssertLaws(t,
|
||||||
|
RA.Eq(eqa),
|
||||||
|
RA.Eq(eqb),
|
||||||
|
RA.Eq(eqc),
|
||||||
|
|
||||||
|
RA.Of[A],
|
||||||
|
RA.Of[B],
|
||||||
|
RA.Of[C],
|
||||||
|
|
||||||
|
RA.Of[func(A) A],
|
||||||
|
RA.Of[func(A) B],
|
||||||
|
RA.Of[func(B) C],
|
||||||
|
RA.Of[func(func(A) B) B],
|
||||||
|
|
||||||
|
RA.MonadMap[A, A],
|
||||||
|
RA.MonadMap[A, B],
|
||||||
|
RA.MonadMap[A, C],
|
||||||
|
RA.MonadMap[B, C],
|
||||||
|
|
||||||
|
RA.MonadMap[func(B) C, func(func(A) B) func(A) C],
|
||||||
|
|
||||||
|
RA.MonadChain[A, A],
|
||||||
|
RA.MonadChain[A, B],
|
||||||
|
RA.MonadChain[A, C],
|
||||||
|
RA.MonadChain[B, C],
|
||||||
|
|
||||||
|
RA.MonadAp[A, A],
|
||||||
|
RA.MonadAp[B, A],
|
||||||
|
RA.MonadAp[C, B],
|
||||||
|
RA.MonadAp[C, A],
|
||||||
|
|
||||||
|
RA.MonadAp[B, func(A) B],
|
||||||
|
RA.MonadAp[func(A) C, func(A) B],
|
||||||
|
|
||||||
|
ab,
|
||||||
|
bc,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
47
array/testing/laws_test.go
Normal file
47
array/testing/laws_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 testing
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
EQ "github.com/IBM/fp-go/eq"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestMonadLaws(t *testing.T) {
|
||||||
|
// some comparison
|
||||||
|
eqa := EQ.FromStrictEquals[bool]()
|
||||||
|
eqb := EQ.FromStrictEquals[int]()
|
||||||
|
eqc := EQ.FromStrictEquals[string]()
|
||||||
|
|
||||||
|
ab := func(a bool) int {
|
||||||
|
if a {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
bc := func(b int) string {
|
||||||
|
return fmt.Sprintf("value %d", b)
|
||||||
|
}
|
||||||
|
|
||||||
|
laws := AssertLaws(t, eqa, eqb, eqc, ab, bc)
|
||||||
|
|
||||||
|
assert.True(t, laws(true))
|
||||||
|
assert.True(t, laws(false))
|
||||||
|
}
|
@@ -32,20 +32,20 @@ type bounded[T any] struct {
|
|||||||
b T
|
b T
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self bounded[T]) Equals(x, y T) bool {
|
func (b bounded[T]) Equals(x, y T) bool {
|
||||||
return self.e(x, y)
|
return b.e(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self bounded[T]) Compare(x, y T) int {
|
func (b bounded[T]) Compare(x, y T) int {
|
||||||
return self.c(x, y)
|
return b.c(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self bounded[T]) Top() T {
|
func (b bounded[T]) Top() T {
|
||||||
return self.t
|
return b.t
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self bounded[T]) Bottom() T {
|
func (b bounded[T]) Bottom() T {
|
||||||
return self.b
|
return b.b
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeBounded creates an instance of a bounded type
|
// MakeBounded creates an instance of a bounded type
|
||||||
|
@@ -15,6 +15,10 @@
|
|||||||
|
|
||||||
package bytes
|
package bytes
|
||||||
|
|
||||||
|
func Empty() []byte {
|
||||||
|
return Monoid.Empty()
|
||||||
|
}
|
||||||
|
|
||||||
func ToString(a []byte) string {
|
func ToString(a []byte) string {
|
||||||
return string(a)
|
return string(a)
|
||||||
}
|
}
|
||||||
|
11
cli/pipe.go
11
cli/pipe.go
@@ -265,10 +265,15 @@ func generatePipe(f *os.File, i int) {
|
|||||||
fmt.Fprintf(f, ", f%d F%d", j, j)
|
fmt.Fprintf(f, ", f%d F%d", j, j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, ") T%d {\n", i)
|
fmt.Fprintf(f, ") T%d {\n", i)
|
||||||
for j := 1; j <= i; j++ {
|
fmt.Fprintf(f, " return ")
|
||||||
fmt.Fprintf(f, " t%d := f%d(t%d)\n", j, j, j-1)
|
for j := i; j >= 1; j-- {
|
||||||
|
fmt.Fprintf(f, "f%d(", j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, " return t%d\n", i)
|
fmt.Fprintf(f, "t0")
|
||||||
|
for j := 1; j <= i; j++ {
|
||||||
|
fmt.Fprintf(f, ")")
|
||||||
|
}
|
||||||
|
fmt.Fprintf(f, "\n")
|
||||||
fmt.Fprintln(f, "}")
|
fmt.Fprintln(f, "}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
40
cli/tuple.go
40
cli/tuple.go
@@ -405,8 +405,6 @@ func generateTupleHelpers(filename string, count int) error {
|
|||||||
|
|
||||||
fmt.Fprintf(f, `
|
fmt.Fprintf(f, `
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"encoding/json"
|
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
O "github.com/IBM/fp-go/ord"
|
O "github.com/IBM/fp-go/ord"
|
||||||
)
|
)
|
||||||
@@ -457,7 +455,7 @@ func generateTupleMarshal(f *os.File, i int) {
|
|||||||
fmt.Fprintf(f, "func (t ")
|
fmt.Fprintf(f, "func (t ")
|
||||||
writeTupleType(f, "T", i)
|
writeTupleType(f, "T", i)
|
||||||
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
fmt.Fprintf(f, ") MarshalJSON() ([]byte, error) {\n")
|
||||||
fmt.Fprintf(f, " return json.Marshal([]any{")
|
fmt.Fprintf(f, " return tupleMarshalJSON(")
|
||||||
// function prototypes
|
// function prototypes
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j <= i; j++ {
|
||||||
if j > 1 {
|
if j > 1 {
|
||||||
@@ -465,7 +463,7 @@ func generateTupleMarshal(f *os.File, i int) {
|
|||||||
}
|
}
|
||||||
fmt.Fprintf(f, "t.F%d", j)
|
fmt.Fprintf(f, "t.F%d", j)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, "})\n")
|
fmt.Fprintf(f, ")\n")
|
||||||
fmt.Fprintf(f, "}\n")
|
fmt.Fprintf(f, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -475,19 +473,12 @@ func generateTupleUnmarshal(f *os.File, i int) {
|
|||||||
fmt.Fprintf(f, "func (t *")
|
fmt.Fprintf(f, "func (t *")
|
||||||
writeTupleType(f, "T", i)
|
writeTupleType(f, "T", i)
|
||||||
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
|
fmt.Fprintf(f, ") UnmarshalJSON(data []byte) error {\n")
|
||||||
fmt.Fprintf(f, " var tmp []json.RawMessage\n")
|
fmt.Fprintf(f, " return tupleUnmarshalJSON(data")
|
||||||
fmt.Fprintf(f, " if err := json.Unmarshal(data, &tmp); err != nil {return err}\n")
|
// function prototypes
|
||||||
fmt.Fprintf(f, " l := len(tmp)\n")
|
|
||||||
// unmarshal fields
|
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j <= i; j++ {
|
||||||
fmt.Fprintf(f, " if l > %d {\n", j-1)
|
fmt.Fprintf(f, ", &t.F%d", j)
|
||||||
fmt.Fprintf(f, " if err := json.Unmarshal(tmp[%d], &t.F%d); err != nil {return err}\n", j-1, j)
|
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, " ")
|
fmt.Fprintf(f, ")\n")
|
||||||
for j := 1; j <= i; j++ {
|
|
||||||
fmt.Fprintf(f, "}")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "\n return nil\n")
|
|
||||||
fmt.Fprintf(f, "}\n")
|
fmt.Fprintf(f, "}\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -570,30 +561,13 @@ func generateTupleString(f *os.File, i int) {
|
|||||||
writeTupleType(f, "T", i)
|
writeTupleType(f, "T", i)
|
||||||
fmt.Fprintf(f, ") String() string {\n")
|
fmt.Fprintf(f, ") String() string {\n")
|
||||||
// convert to string
|
// convert to string
|
||||||
fmt.Fprintf(f, " return fmt.Sprintf(\"Tuple%d[", i)
|
fmt.Fprint(f, " return tupleString(")
|
||||||
for j := 1; j <= i; j++ {
|
|
||||||
if j > 1 {
|
|
||||||
fmt.Fprintf(f, ", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "%s", "%T")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "](")
|
|
||||||
for j := 1; j <= i; j++ {
|
|
||||||
if j > 1 {
|
|
||||||
fmt.Fprintf(f, ", ")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, "%s", "%v")
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, ")\", ")
|
|
||||||
for j := 1; j <= i; j++ {
|
for j := 1; j <= i; j++ {
|
||||||
if j > 1 {
|
if j > 1 {
|
||||||
fmt.Fprintf(f, ", ")
|
fmt.Fprintf(f, ", ")
|
||||||
}
|
}
|
||||||
fmt.Fprintf(f, "t.F%d", j)
|
fmt.Fprintf(f, "t.F%d", j)
|
||||||
}
|
}
|
||||||
for j := 1; j <= i; j++ {
|
|
||||||
fmt.Fprintf(f, ", t.F%d", j)
|
|
||||||
}
|
|
||||||
fmt.Fprintf(f, ")\n")
|
fmt.Fprintf(f, ")\n")
|
||||||
fmt.Fprintf(f, "}\n")
|
fmt.Fprintf(f, "}\n")
|
||||||
}
|
}
|
||||||
|
@@ -37,7 +37,7 @@ func Of[E, A any](m M.Monoid[E]) func(A) Const[E, A] {
|
|||||||
return F.Constant1[A](Make[E, A](m.Empty()))
|
return F.Constant1[A](Make[E, A](m.Empty()))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadMap[E, A, B any](fa Const[E, A], f func(A) B) Const[E, B] {
|
func MonadMap[E, A, B any](fa Const[E, A], _ func(A) B) Const[E, B] {
|
||||||
return Make[E, B](fa.value)
|
return Make[E, B](fa.value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
68
context/readereither/bind.go
Normal file
68
context/readereither/bind.go
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
// 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 readereither
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
G "github.com/IBM/fp-go/readereither/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) ReaderEither[S] {
|
||||||
|
return G.Do[ReaderEither[S], context.Context, error, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) ReaderEither[T],
|
||||||
|
) func(ReaderEither[S1]) ReaderEither[S2] {
|
||||||
|
return G.Bind[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(ReaderEither[S1]) ReaderEither[S2] {
|
||||||
|
return G.Let[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(ReaderEither[S1]) ReaderEither[S2] {
|
||||||
|
return G.LetTo[ReaderEither[S1], ReaderEither[S2], context.Context, error, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(ReaderEither[T]) ReaderEither[S1] {
|
||||||
|
return G.BindTo[ReaderEither[S1], ReaderEither[T], context.Context, error, S1, T](setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa ReaderEither[T],
|
||||||
|
) func(ReaderEither[S1]) ReaderEither[S2] {
|
||||||
|
return G.ApS[ReaderEither[S1], ReaderEither[S2], ReaderEither[T], context.Context, error, S1, S2, T](setter, fa)
|
||||||
|
}
|
58
context/readereither/bind_test.go
Normal file
58
context/readereither/bind_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package readereither
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) ReaderEither[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) ReaderEither[string] {
|
||||||
|
return Of("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of("John")),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
|
||||||
|
}
|
67
context/readerioeither/bind.go
Normal file
67
context/readerioeither/bind.go
Normal file
@@ -0,0 +1,67 @@
|
|||||||
|
// 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"
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) ReaderIOEither[S] {
|
||||||
|
return G.Do[ReaderIOEither[S], IOE.IOEither[error, S], S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) ReaderIOEither[T],
|
||||||
|
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||||
|
return G.Bind[ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||||
|
return G.Let[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||||
|
return G.LetTo[ReaderIOEither[S1], ReaderIOEither[S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(ReaderIOEither[T]) ReaderIOEither[S1] {
|
||||||
|
return G.BindTo[ReaderIOEither[S1], ReaderIOEither[T], IOE.IOEither[error, S1], IOE.IOEither[error, T], S1, T](setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa ReaderIOEither[T],
|
||||||
|
) func(ReaderIOEither[S1]) ReaderIOEither[S2] {
|
||||||
|
return G.ApS[ReaderIOEither[func(T) S2], ReaderIOEither[S1], ReaderIOEither[S2], ReaderIOEither[T], IOE.IOEither[error, func(T) S2], IOE.IOEither[error, S1], IOE.IOEither[error, S2], IOE.IOEither[error, T], S1, S2, T](setter, fa)
|
||||||
|
}
|
58
context/readerioeither/bind_test.go
Normal file
58
context/readerioeither/bind_test.go
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package readerioeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) ReaderIOEither[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) ReaderIOEither[string] {
|
||||||
|
return Of("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of("John")),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
|
||||||
|
}
|
@@ -47,5 +47,5 @@ func ExampleReadFile() {
|
|||||||
fmt.Println(result())
|
fmt.Println(result())
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Right[<nil>, string](Carsten)
|
// Right[string](Carsten)
|
||||||
}
|
}
|
||||||
|
92
context/readerioeither/generic/bind.go
Normal file
92
context/readerioeither/generic/bind.go
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GRS ~func(context.Context) GS, GS ~func() ET.Either[error, S], S any](
|
||||||
|
empty S,
|
||||||
|
) GRS {
|
||||||
|
return Of[GRS, GS, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GRT,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GRS1, GRS2, GS1, GS2, S1, S2],
|
||||||
|
Map[GRT, GRS2, GT, GS2, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GRS1, GRS2, GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GRS1, GRS2, GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GRS1 ~func(context.Context) GS1, GRT ~func(context.Context) GT, GS1 ~func() ET.Either[error, S1], GT ~func() ET.Either[error, T], S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GRT) GRS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GRT, GRS1, GT, GS1, T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[GRTS1 ~func(context.Context) GTS1, GRS1 ~func(context.Context) GS1, GRS2 ~func(context.Context) GS2, GRT ~func(context.Context) GT, GTS1 ~func() ET.Either[error, func(T) S2], GS1 ~func() ET.Either[error, S1], GS2 ~func() ET.Either[error, S2], GT ~func() ET.Either[error, T], S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GRT,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GRS2, GRTS1, GRT, GS2, GTS1, GT],
|
||||||
|
Map[GRS1, GRTS1, GS1, GTS1, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@@ -182,10 +182,7 @@ func withCancelCauseFunc[
|
|||||||
ma,
|
ma,
|
||||||
IOE.Swap[GIOA, func() E.Either[A, error]],
|
IOE.Swap[GIOA, func() E.Either[A, error]],
|
||||||
IOE.ChainFirstIOK[func() E.Either[A, error], func() any](func(err error) func() any {
|
IOE.ChainFirstIOK[func() E.Either[A, error], func() any](func(err error) func() any {
|
||||||
return IO.MakeIO[func() any](func() any {
|
return IO.FromImpure[func() any](func() { cancel(err) })
|
||||||
cancel(err)
|
|
||||||
return nil
|
|
||||||
})
|
|
||||||
}),
|
}),
|
||||||
IOE.Swap[func() E.Either[A, error], GIOA],
|
IOE.Swap[func() E.Either[A, error], GIOA],
|
||||||
)
|
)
|
||||||
|
@@ -61,7 +61,7 @@ func Requester(builder *R.Builder) RIOEH.Requester {
|
|||||||
return F.Pipe5(
|
return F.Pipe5(
|
||||||
builder.GetBody(),
|
builder.GetBody(),
|
||||||
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
||||||
E.Ap[func(string) RIOE.ReaderIOEither[*http.Request]](builder.GetTargetUrl()),
|
E.Ap[func(string) RIOE.ReaderIOEither[*http.Request]](builder.GetTargetURL()),
|
||||||
E.Flap[error, RIOE.ReaderIOEither[*http.Request]](builder.GetMethod()),
|
E.Flap[error, RIOE.ReaderIOEither[*http.Request]](builder.GetMethod()),
|
||||||
E.GetOrElse(RIOE.Left[*http.Request]),
|
E.GetOrElse(RIOE.Left[*http.Request]),
|
||||||
RIOE.Map(func(req *http.Request) *http.Request {
|
RIOE.Map(func(req *http.Request) *http.Request {
|
||||||
|
@@ -32,12 +32,12 @@ import (
|
|||||||
func TestBuilderWithQuery(t *testing.T) {
|
func TestBuilderWithQuery(t *testing.T) {
|
||||||
// add some query
|
// add some query
|
||||||
withLimit := R.WithQueryArg("limit")("10")
|
withLimit := R.WithQueryArg("limit")("10")
|
||||||
withUrl := R.WithUrl("http://www.example.org?a=b")
|
withURL := R.WithURL("http://www.example.org?a=b")
|
||||||
|
|
||||||
b := F.Pipe2(
|
b := F.Pipe2(
|
||||||
R.Default,
|
R.Default,
|
||||||
withLimit,
|
withLimit,
|
||||||
withUrl,
|
withURL,
|
||||||
)
|
)
|
||||||
|
|
||||||
req := F.Pipe3(
|
req := F.Pipe3(
|
||||||
|
@@ -103,12 +103,19 @@ func ReadText(client Client) func(Requester) RIOE.ReaderIOEither[string] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadJson sends a request, reads the response and parses the response as JSON
|
// ReadJson sends a request, reads the response and parses the response as JSON
|
||||||
|
//
|
||||||
|
// Deprecated: use [ReadJSON] instead
|
||||||
func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
func ReadJson[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||||
|
return ReadJSON[A](client)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ReadJSON sends a request, reads the response and parses the response as JSON
|
||||||
|
func ReadJSON[A any](client Client) func(Requester) RIOE.ReaderIOEither[A] {
|
||||||
return F.Flow3(
|
return F.Flow3(
|
||||||
ReadFullResponse(client),
|
ReadFullResponse(client),
|
||||||
RIOE.ChainFirstEitherK(F.Flow2(
|
RIOE.ChainFirstEitherK(F.Flow2(
|
||||||
H.Response,
|
H.Response,
|
||||||
H.ValidateJsonResponse,
|
H.ValidateJSONResponse,
|
||||||
)),
|
)),
|
||||||
RIOE.ChainEitherK(F.Flow2(
|
RIOE.ChainEitherK(F.Flow2(
|
||||||
H.Body,
|
H.Body,
|
||||||
|
@@ -31,7 +31,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type PostItem struct {
|
type PostItem struct {
|
||||||
UserId uint `json:"userId"`
|
UserID uint `json:"userId"`
|
||||||
Id uint `json:"id"`
|
Id uint `json:"id"`
|
||||||
Title string `json:"title"`
|
Title string `json:"title"`
|
||||||
Body string `json:"body"`
|
Body string `json:"body"`
|
||||||
@@ -84,7 +84,7 @@ func TestSendSingleRequest(t *testing.T) {
|
|||||||
|
|
||||||
req1 := MakeGetRequest("https://jsonplaceholder.typicode.com/posts/1")
|
req1 := MakeGetRequest("https://jsonplaceholder.typicode.com/posts/1")
|
||||||
|
|
||||||
readItem := ReadJson[PostItem](client)
|
readItem := ReadJSON[PostItem](client)
|
||||||
|
|
||||||
resp1 := readItem(req1)
|
resp1 := readItem(req1)
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ func TestSendSingleRequestWithHeaderUnsafe(t *testing.T) {
|
|||||||
R.Map(setHeaderUnsafe("Content-Type", "text/html")),
|
R.Map(setHeaderUnsafe("Content-Type", "text/html")),
|
||||||
)
|
)
|
||||||
|
|
||||||
readItem := ReadJson[PostItem](client)
|
readItem := ReadJSON[PostItem](client)
|
||||||
|
|
||||||
resp1 := F.Pipe2(
|
resp1 := F.Pipe2(
|
||||||
req1,
|
req1,
|
||||||
@@ -140,7 +140,7 @@ func TestSendSingleRequestWithHeaderSafe(t *testing.T) {
|
|||||||
WithHeader("Content-Type", "text/html").
|
WithHeader("Content-Type", "text/html").
|
||||||
Build()
|
Build()
|
||||||
|
|
||||||
readItem := ReadJson[PostItem](client)
|
readItem := ReadJSON[PostItem](client)
|
||||||
|
|
||||||
response := F.Pipe2(
|
response := F.Pipe2(
|
||||||
request,
|
request,
|
||||||
|
@@ -127,7 +127,7 @@ func MakeInjector(providers []Provider) InjectableFactory {
|
|||||||
var resolved sync.Map
|
var resolved sync.Map
|
||||||
|
|
||||||
// provide a mapping for all providers
|
// provide a mapping for all providers
|
||||||
factoryById := assembleProviders(providers)
|
factoryByID := assembleProviders(providers)
|
||||||
|
|
||||||
// the actual factory, we need lazy initialization
|
// the actual factory, we need lazy initialization
|
||||||
var injFct InjectableFactory
|
var injFct InjectableFactory
|
||||||
@@ -149,7 +149,7 @@ func MakeInjector(providers []Provider) InjectableFactory {
|
|||||||
T.Map2(F.Flow3(
|
T.Map2(F.Flow3(
|
||||||
Dependency.Id,
|
Dependency.Id,
|
||||||
R.Lookup[ProviderFactory, string],
|
R.Lookup[ProviderFactory, string],
|
||||||
I.Ap[O.Option[ProviderFactory]](factoryById),
|
I.Ap[O.Option[ProviderFactory]](factoryByID),
|
||||||
), handleMissingProvider),
|
), handleMissingProvider),
|
||||||
T.Tupled2(O.MonadGetOrElse[ProviderFactory]),
|
T.Tupled2(O.MonadGetOrElse[ProviderFactory]),
|
||||||
IG.Ap[ProviderFactory](injFct),
|
IG.Ap[ProviderFactory](injFct),
|
||||||
|
39
di/token.go
39
di/token.go
@@ -65,34 +65,38 @@ type MultiInjectionToken[T any] interface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// makeID creates a generator of unique string IDs
|
// makeID creates a generator of unique string IDs
|
||||||
func makeId() IO.IO[string] {
|
func makeID() IO.IO[string] {
|
||||||
var count atomic.Int64
|
var count atomic.Int64
|
||||||
return IO.MakeIO(func() string {
|
return IO.MakeIO(func() string {
|
||||||
return strconv.FormatInt(count.Add(1), 16)
|
return strconv.FormatInt(count.Add(1), 16)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// genId is the common generator of unique string IDs
|
// genID is the common generator of unique string IDs
|
||||||
var genId = makeId()
|
var genID = makeID()
|
||||||
|
|
||||||
type token[T any] struct {
|
type tokenBase struct {
|
||||||
name string
|
name string
|
||||||
id string
|
id string
|
||||||
flag int
|
flag int
|
||||||
toType func(val any) E.Either[error, T]
|
|
||||||
providerFactory O.Option[DIE.ProviderFactory]
|
providerFactory O.Option[DIE.ProviderFactory]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type token[T any] struct {
|
||||||
|
base *tokenBase
|
||||||
|
toType func(val any) E.Either[error, T]
|
||||||
|
}
|
||||||
|
|
||||||
func (t *token[T]) Id() string {
|
func (t *token[T]) Id() string {
|
||||||
return t.id
|
return t.base.id
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *token[T]) Flag() int {
|
func (t *token[T]) Flag() int {
|
||||||
return t.flag
|
return t.base.flag
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *token[T]) String() string {
|
func (t *token[T]) String() string {
|
||||||
return t.name
|
return t.base.name
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *token[T]) Unerase(val any) E.Either[error, T] {
|
func (t *token[T]) Unerase(val any) E.Either[error, T] {
|
||||||
@@ -100,11 +104,14 @@ func (t *token[T]) Unerase(val any) E.Either[error, T] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *token[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
func (t *token[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
||||||
return t.providerFactory
|
return t.base.providerFactory
|
||||||
|
}
|
||||||
|
func makeTokenBase(name string, id string, typ int, providerFactory O.Option[DIE.ProviderFactory]) *tokenBase {
|
||||||
|
return &tokenBase{name, id, typ, providerFactory}
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeToken[T any](name string, id string, typ int, unerase func(val any) E.Either[error, T], providerFactory O.Option[DIE.ProviderFactory]) Dependency[T] {
|
func makeToken[T any](name string, id string, typ int, unerase func(val any) E.Either[error, T], providerFactory O.Option[DIE.ProviderFactory]) Dependency[T] {
|
||||||
return &token[T]{name, id, typ, unerase, providerFactory}
|
return &token[T]{makeTokenBase(name, id, typ, providerFactory), unerase}
|
||||||
}
|
}
|
||||||
|
|
||||||
type injectionToken[T any] struct {
|
type injectionToken[T any] struct {
|
||||||
@@ -136,7 +143,7 @@ func (i *injectionToken[T]) IOOption() Dependency[IOO.IOOption[T]] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (i *injectionToken[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
func (i *injectionToken[T]) ProviderFactory() O.Option[DIE.ProviderFactory] {
|
||||||
return i.providerFactory
|
return i.base.providerFactory
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *multiInjectionToken[T]) Container() InjectionToken[[]T] {
|
func (m *multiInjectionToken[T]) Container() InjectionToken[[]T] {
|
||||||
@@ -149,10 +156,10 @@ func (m *multiInjectionToken[T]) Item() InjectionToken[T] {
|
|||||||
|
|
||||||
// makeToken create a unique [InjectionToken] for a specific type
|
// makeToken create a unique [InjectionToken] for a specific type
|
||||||
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
||||||
id := genId()
|
id := genID()
|
||||||
toIdentity := toType[T]()
|
toIdentity := toType[T]()
|
||||||
return &injectionToken[T]{
|
return &injectionToken[T]{
|
||||||
token[T]{name, id, DIE.Identity, toIdentity, providerFactory},
|
token[T]{makeTokenBase(name, id, DIE.Identity, providerFactory), toIdentity},
|
||||||
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", name), id, DIE.Option, toOptionType(toIdentity), providerFactory),
|
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", name), id, DIE.Option, toOptionType(toIdentity), providerFactory),
|
||||||
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", name), id, DIE.IOEither, toIOEitherType(toIdentity), providerFactory),
|
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", name), id, DIE.IOEither, toIOEitherType(toIdentity), providerFactory),
|
||||||
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", name), id, DIE.IOOption, toIOOptionType(toIdentity), providerFactory),
|
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", name), id, DIE.IOOption, toIOOptionType(toIdentity), providerFactory),
|
||||||
@@ -171,7 +178,7 @@ func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactor
|
|||||||
|
|
||||||
// MakeMultiToken creates a [MultiInjectionToken]
|
// MakeMultiToken creates a [MultiInjectionToken]
|
||||||
func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
|
func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
|
||||||
id := genId()
|
id := genID()
|
||||||
toItem := toType[T]()
|
toItem := toType[T]()
|
||||||
toContainer := toArrayType(toItem)
|
toContainer := toArrayType(toItem)
|
||||||
containerName := fmt.Sprintf("Container[%s]", name)
|
containerName := fmt.Sprintf("Container[%s]", name)
|
||||||
@@ -180,14 +187,14 @@ func MakeMultiToken[T any](name string) MultiInjectionToken[T] {
|
|||||||
providerFactory := O.None[DIE.ProviderFactory]()
|
providerFactory := O.None[DIE.ProviderFactory]()
|
||||||
// container
|
// container
|
||||||
container := &injectionToken[[]T]{
|
container := &injectionToken[[]T]{
|
||||||
token[[]T]{containerName, id, DIE.Multi | DIE.Identity, toContainer, providerFactory},
|
token[[]T]{makeTokenBase(containerName, id, DIE.Multi|DIE.Identity, providerFactory), toContainer},
|
||||||
makeToken[O.Option[[]T]](fmt.Sprintf("Option[%s]", containerName), id, DIE.Multi|DIE.Option, toOptionType(toContainer), providerFactory),
|
makeToken[O.Option[[]T]](fmt.Sprintf("Option[%s]", containerName), id, DIE.Multi|DIE.Option, toOptionType(toContainer), providerFactory),
|
||||||
makeToken[IOE.IOEither[error, []T]](fmt.Sprintf("IOEither[%s]", containerName), id, DIE.Multi|DIE.IOEither, toIOEitherType(toContainer), providerFactory),
|
makeToken[IOE.IOEither[error, []T]](fmt.Sprintf("IOEither[%s]", containerName), id, DIE.Multi|DIE.IOEither, toIOEitherType(toContainer), providerFactory),
|
||||||
makeToken[IOO.IOOption[[]T]](fmt.Sprintf("IOOption[%s]", containerName), id, DIE.Multi|DIE.IOOption, toIOOptionType(toContainer), providerFactory),
|
makeToken[IOO.IOOption[[]T]](fmt.Sprintf("IOOption[%s]", containerName), id, DIE.Multi|DIE.IOOption, toIOOptionType(toContainer), providerFactory),
|
||||||
}
|
}
|
||||||
// item
|
// item
|
||||||
item := &injectionToken[T]{
|
item := &injectionToken[T]{
|
||||||
token[T]{itemName, id, DIE.Item | DIE.Identity, toItem, providerFactory},
|
token[T]{makeTokenBase(itemName, id, DIE.Item|DIE.Identity, providerFactory), toItem},
|
||||||
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", itemName), id, DIE.Item|DIE.Option, toOptionType(toItem), providerFactory),
|
makeToken[O.Option[T]](fmt.Sprintf("Option[%s]", itemName), id, DIE.Item|DIE.Option, toOptionType(toItem), providerFactory),
|
||||||
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", itemName), id, DIE.Item|DIE.IOEither, toIOEitherType(toItem), providerFactory),
|
makeToken[IOE.IOEither[error, T]](fmt.Sprintf("IOEither[%s]", itemName), id, DIE.Item|DIE.IOEither, toIOEitherType(toItem), providerFactory),
|
||||||
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", itemName), id, DIE.Item|DIE.IOOption, toIOOptionType(toItem), providerFactory),
|
makeToken[IOO.IOOption[T]](fmt.Sprintf("IOOption[%s]", itemName), id, DIE.Item|DIE.IOOption, toIOOptionType(toItem), providerFactory),
|
||||||
|
15
di/utils.go
15
di/utils.go
@@ -25,6 +25,13 @@ import (
|
|||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
toOptionAny = toType[O.Option[any]]()
|
||||||
|
toIOEitherAny = toType[IOE.IOEither[error, any]]()
|
||||||
|
toIOOptionAny = toType[IOO.IOOption[any]]()
|
||||||
|
toArrayAny = toType[[]any]()
|
||||||
|
)
|
||||||
|
|
||||||
// asDependency converts a generic type to a [DIE.Dependency]
|
// asDependency converts a generic type to a [DIE.Dependency]
|
||||||
func asDependency[T DIE.Dependency](t T) DIE.Dependency {
|
func asDependency[T DIE.Dependency](t T) DIE.Dependency {
|
||||||
return t
|
return t
|
||||||
@@ -38,7 +45,7 @@ func toType[T any]() func(t any) E.Either[error, T] {
|
|||||||
// toOptionType converts an any to an Option[any] and then to an Option[T]
|
// toOptionType converts an any to an Option[any] and then to an Option[T]
|
||||||
func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, O.Option[T]] {
|
func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, O.Option[T]] {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
toType[O.Option[any]](),
|
toOptionAny,
|
||||||
E.Chain(O.Fold(
|
E.Chain(O.Fold(
|
||||||
F.Nullary2(O.None[T], E.Of[error, O.Option[T]]),
|
F.Nullary2(O.None[T], E.Of[error, O.Option[T]]),
|
||||||
F.Flow2(
|
F.Flow2(
|
||||||
@@ -52,7 +59,7 @@ func toOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either
|
|||||||
// toIOEitherType converts an any to an IOEither[error, any] and then to an IOEither[error, T]
|
// toIOEitherType converts an any to an IOEither[error, any] and then to an IOEither[error, T]
|
||||||
func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOE.IOEither[error, T]] {
|
func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOE.IOEither[error, T]] {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
toType[IOE.IOEither[error, any]](),
|
toIOEitherAny,
|
||||||
E.Map[error](IOE.ChainEitherK(item)),
|
E.Map[error](IOE.ChainEitherK(item)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -60,7 +67,7 @@ func toIOEitherType[T any](item func(any) E.Either[error, T]) func(t any) E.Eith
|
|||||||
// toIOOptionType converts an any to an IOOption[any] and then to an IOOption[T]
|
// toIOOptionType converts an any to an IOOption[any] and then to an IOOption[T]
|
||||||
func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOO.IOOption[T]] {
|
func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, IOO.IOOption[T]] {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
toType[IOO.IOOption[any]](),
|
toIOOptionAny,
|
||||||
E.Map[error](IOO.ChainOptionK(F.Flow2(
|
E.Map[error](IOO.ChainOptionK(F.Flow2(
|
||||||
item,
|
item,
|
||||||
E.ToOption[error, T],
|
E.ToOption[error, T],
|
||||||
@@ -71,7 +78,7 @@ func toIOOptionType[T any](item func(any) E.Either[error, T]) func(t any) E.Eith
|
|||||||
// toArrayType converts an any to a []T
|
// toArrayType converts an any to a []T
|
||||||
func toArrayType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, []T] {
|
func toArrayType[T any](item func(any) E.Either[error, T]) func(t any) E.Either[error, []T] {
|
||||||
return F.Flow2(
|
return F.Flow2(
|
||||||
toType[[]any](),
|
toArrayAny,
|
||||||
E.Chain(E.TraverseArray(item)),
|
E.Chain(E.TraverseArray(item)),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
89
either/bind.go
Normal file
89
either/bind.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// 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 (
|
||||||
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[E, S any](
|
||||||
|
empty S,
|
||||||
|
) Either[E, S] {
|
||||||
|
return Of[E](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) Either[E, T],
|
||||||
|
) func(Either[E, S1]) Either[E, S2] {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[E, S1, S2],
|
||||||
|
Map[E, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[E, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(Either[E, S1]) Either[E, S2] {
|
||||||
|
return F.Let(
|
||||||
|
Map[E, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[E, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(Either[E, S1]) Either[E, S2] {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[E, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(Either[E, T]) Either[E, S1] {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[E, T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa Either[E, T],
|
||||||
|
) func(Either[E, S1]) Either[E, S2] {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[S2, E, T],
|
||||||
|
Map[E, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
56
either/bind_test.go
Normal file
56
either/bind_test.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package either
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) Either[error, string] {
|
||||||
|
return Of[error]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Either[error, string] {
|
||||||
|
return Of[error]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[error](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res, Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[error](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[error]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[error]("John")),
|
||||||
|
Map[error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res, Of[error]("John Doe"))
|
||||||
|
}
|
@@ -20,30 +20,45 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
|
either struct {
|
||||||
Either[E, A any] struct {
|
|
||||||
isLeft bool
|
isLeft bool
|
||||||
left E
|
value any
|
||||||
right A
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Either defines a data structure that logically holds either an E or an A. The flag discriminates the cases
|
||||||
|
Either[E, A any] either
|
||||||
)
|
)
|
||||||
|
|
||||||
// String prints some debug info for the object
|
// String prints some debug info for the object
|
||||||
func (s Either[E, A]) String() string {
|
//
|
||||||
|
// go:noinline
|
||||||
|
func eitherString(s *either) string {
|
||||||
if s.isLeft {
|
if s.isLeft {
|
||||||
return fmt.Sprintf("Left[%T, %T](%v)", s.left, s.right, s.left)
|
return fmt.Sprintf("Left[%T](%v)", s.value, s.value)
|
||||||
}
|
}
|
||||||
return fmt.Sprintf("Right[%T, %T](%v)", s.left, s.right, s.right)
|
return fmt.Sprintf("Right[%T](%v)", s.value, s.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Format prints some debug info for the object
|
||||||
|
//
|
||||||
|
// go:noinline
|
||||||
|
func eitherFormat(e *either, f fmt.State, c rune) {
|
||||||
|
switch c {
|
||||||
|
case 's':
|
||||||
|
fmt.Fprint(f, eitherString(e))
|
||||||
|
default:
|
||||||
|
fmt.Fprint(f, eitherString(e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// String prints some debug info for the object
|
||||||
|
func (s Either[E, A]) String() string {
|
||||||
|
return eitherString((*either)(&s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Format prints some debug info for the object
|
// Format prints some debug info for the object
|
||||||
func (s Either[E, A]) Format(f fmt.State, c rune) {
|
func (s Either[E, A]) Format(f fmt.State, c rune) {
|
||||||
switch c {
|
eitherFormat((*either)(&s), f, c)
|
||||||
case 's':
|
|
||||||
fmt.Fprint(f, s.String())
|
|
||||||
default:
|
|
||||||
fmt.Fprint(f, s.String())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
// IsLeft tests if the [Either] is a left value. Rather use [Fold] if you need to access the values. Inverse is [IsRight].
|
||||||
@@ -58,23 +73,29 @@ func IsRight[E, A any](val Either[E, A]) bool {
|
|||||||
|
|
||||||
// Left creates a new instance of an [Either] representing the left value.
|
// Left creates a new instance of an [Either] representing the left value.
|
||||||
func Left[A, E any](value E) Either[E, A] {
|
func Left[A, E any](value E) Either[E, A] {
|
||||||
return Either[E, A]{isLeft: true, left: value}
|
return Either[E, A]{true, value}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Right creates a new instance of an [Either] representing the right value.
|
// Right creates a new instance of an [Either] representing the right value.
|
||||||
func Right[E, A any](value A) Either[E, A] {
|
func Right[E, A any](value A) Either[E, A] {
|
||||||
return Either[E, A]{isLeft: false, right: value}
|
return Either[E, A]{false, value}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadFold extracts the values from an [Either] by invoking the [onLeft] callback or the [onRight] callback depending on the case
|
// MonadFold extracts the values from an [Either] by invoking the [onLeft] callback or the [onRight] callback depending on the case
|
||||||
func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B {
|
func MonadFold[E, A, B any](ma Either[E, A], onLeft func(e E) B, onRight func(a A) B) B {
|
||||||
if ma.isLeft {
|
if ma.isLeft {
|
||||||
return onLeft(ma.left)
|
return onLeft(ma.value.(E))
|
||||||
}
|
}
|
||||||
return onRight(ma.right)
|
return onRight(ma.value.(A))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unwrap converts an [Either] into the idiomatic tuple
|
// Unwrap converts an [Either] into the idiomatic tuple
|
||||||
func Unwrap[E, A any](ma Either[E, A]) (A, E) {
|
func Unwrap[E, A any](ma Either[E, A]) (A, E) {
|
||||||
return ma.right, ma.left
|
if ma.isLeft {
|
||||||
|
var a A
|
||||||
|
return a, ma.value.(E)
|
||||||
|
} else {
|
||||||
|
var e E
|
||||||
|
return ma.value.(A), e
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -22,6 +22,7 @@ package either
|
|||||||
import (
|
import (
|
||||||
E "github.com/IBM/fp-go/errors"
|
E "github.com/IBM/fp-go/errors"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
FC "github.com/IBM/fp-go/internal/functor"
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
L "github.com/IBM/fp-go/lazy"
|
L "github.com/IBM/fp-go/lazy"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
@@ -64,7 +65,7 @@ func MonadMapTo[E, A, B any](fa Either[E, A], b B) Either[E, B] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MapTo[E, A, B any](b B) func(Either[E, A]) Either[E, B] {
|
func MapTo[E, A, B any](b B) func(Either[E, A]) Either[E, B] {
|
||||||
return F.Bind2nd(MonadMapTo[E, A, B], b)
|
return Map[E](F.Constant1[A](b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadMapLeft[E1, A, E2 any](fa Either[E1, A], f func(E1) E2) Either[E2, A] {
|
func MonadMapLeft[E1, A, E2 any](fa Either[E1, A], f func(E1) E2) Either[E2, A] {
|
||||||
@@ -77,7 +78,7 @@ func Map[E, A, B any](f func(a A) B) func(fa Either[E, A]) Either[E, B] {
|
|||||||
|
|
||||||
// MapLeft applies a mapping function to the error channel
|
// MapLeft applies a mapping function to the error channel
|
||||||
func MapLeft[A, E1, E2 any](f func(E1) E2) func(fa Either[E1, A]) Either[E2, A] {
|
func MapLeft[A, E1, E2 any](f func(E1) E2) func(fa Either[E1, A]) Either[E2, A] {
|
||||||
return F.Bind2nd(MonadMapLeft[E1, A, E2], f)
|
return Fold(F.Flow2(f, Left[A, E2]), Right[E2, A])
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E, B] {
|
func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E, B] {
|
||||||
@@ -85,12 +86,15 @@ func MonadChain[E, A, B any](fa Either[E, A], f func(a A) Either[E, B]) Either[E
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainFirst[E, A, B any](ma Either[E, A], f func(a A) Either[E, B]) Either[E, A] {
|
func MonadChainFirst[E, A, B any](ma Either[E, A], f func(a A) Either[E, B]) Either[E, A] {
|
||||||
return MonadChain(ma, func(a A) Either[E, A] {
|
return C.MonadChainFirst(
|
||||||
return MonadMap(f(a), F.Constant1[B](a))
|
MonadChain[E, A, A],
|
||||||
})
|
MonadMap[E, B, A],
|
||||||
|
ma,
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainTo[A, E, B any](ma Either[E, A], mb Either[E, B]) Either[E, B] {
|
func MonadChainTo[A, E, B any](_ Either[E, A], mb Either[E, B]) Either[E, B] {
|
||||||
return mb
|
return mb
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,15 +110,19 @@ func ChainOptionK[A, B, E any](onNone func() E) func(func(A) O.Option[B]) func(E
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainTo[A, E, B any](mb Either[E, B]) func(Either[E, A]) Either[E, B] {
|
func ChainTo[A, E, B any](mb Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||||
return F.Bind2nd(MonadChainTo[A, E, B], mb)
|
return F.Constant1[Either[E, A]](mb)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Chain[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, B] {
|
func Chain[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||||
return F.Bind2nd(MonadChain[E, A, B], f)
|
return Fold(Left[B, E], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirst[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, A] {
|
func ChainFirst[E, A, B any](f func(a A) Either[E, B]) func(Either[E, A]) Either[E, A] {
|
||||||
return F.Bind2nd(MonadChainFirst[E, A, B], f)
|
return C.ChainFirst(
|
||||||
|
Chain[E, A, A],
|
||||||
|
Map[E, B, A],
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
|
func Flatten[E, A any](mma Either[E, Either[E, A]]) Either[E, A] {
|
||||||
@@ -251,7 +259,7 @@ func MonadFlap[E, B, A any](fab Either[E, func(A) B], a A) Either[E, B] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Flap[E, B, A any](a A) func(Either[E, func(A) B]) Either[E, B] {
|
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)
|
return FC.Flap(Map[E, func(A) B, B], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
|
func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] {
|
||||||
|
@@ -17,6 +17,7 @@ package either
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
@@ -26,12 +27,6 @@ import (
|
|||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestDefault(t *testing.T) {
|
|
||||||
var e Either[error, string]
|
|
||||||
|
|
||||||
assert.Equal(t, Of[error](""), e)
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestIsLeft(t *testing.T) {
|
func TestIsLeft(t *testing.T) {
|
||||||
err := errors.New("Some error")
|
err := errors.New("Some error")
|
||||||
withError := Left[string](err)
|
withError := Left[string](err)
|
||||||
@@ -115,3 +110,13 @@ func TestFromOption(t *testing.T) {
|
|||||||
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
assert.Equal(t, Left[int]("none"), FromOption[int](F.Constant("none"))(O.None[int]()))
|
||||||
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
assert.Equal(t, Right[string](1), FromOption[int](F.Constant("none"))(O.Some(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestStringer(t *testing.T) {
|
||||||
|
e := Of[error]("foo")
|
||||||
|
exp := "Right[string](foo)"
|
||||||
|
|
||||||
|
assert.Equal(t, exp, e.String())
|
||||||
|
|
||||||
|
var s fmt.Stringer = e
|
||||||
|
assert.Equal(t, exp, s.String())
|
||||||
|
}
|
||||||
|
@@ -34,7 +34,7 @@ func Eq[E, A any](e EQ.Eq[E], a EQ.Eq[A]) EQ.Eq[Either[E, A]] {
|
|||||||
return EQ.FromEquals(F.Uncurry2(fld))
|
return EQ.FromEquals(F.Uncurry2(fld))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[E, A comparable]() EQ.Eq[Either[E, A]] {
|
func FromStrictEquals[E, A comparable]() EQ.Eq[Either[E, A]] {
|
||||||
return Eq(EQ.FromStrictEquals[E](), EQ.FromStrictEquals[A]())
|
return Eq(EQ.FromStrictEquals[E](), EQ.FromStrictEquals[A]())
|
||||||
}
|
}
|
||||||
|
@@ -48,11 +48,11 @@ func ExampleEither_creation() {
|
|||||||
fmt.Println(rightFromPred)
|
fmt.Println(rightFromPred)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Left[*errors.errorString, string](some error)
|
// Left[*errors.errorString](some error)
|
||||||
// Right[<nil>, string](value)
|
// Right[string](value)
|
||||||
// Left[*errors.errorString, *string](value was nil)
|
// Left[*errors.errorString](value was nil)
|
||||||
// true
|
// true
|
||||||
// Left[*errors.errorString, int](3 is an odd number)
|
// Left[*errors.errorString](3 is an odd number)
|
||||||
// Right[<nil>, int](4)
|
// Right[int](4)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -53,8 +53,8 @@ func ExampleEither_extraction() {
|
|||||||
fmt.Println(doubleFromRightBis)
|
fmt.Println(doubleFromRightBis)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Left[*errors.errorString, int](Division by Zero!)
|
// Left[*errors.errorString](Division by Zero!)
|
||||||
// Right[<nil>, int](10)
|
// Right[int](10)
|
||||||
// 0
|
// 0
|
||||||
// 10
|
// 10
|
||||||
// 0
|
// 0
|
||||||
|
43
either/monad.go
Normal file
43
either/monad.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2024 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 (
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
)
|
||||||
|
|
||||||
|
type eitherMonad[E, A, B any] struct{}
|
||||||
|
|
||||||
|
func (o *eitherMonad[E, A, B]) Of(a A) Either[E, A] {
|
||||||
|
return Of[E, A](a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *eitherMonad[E, A, B]) Map(f func(A) B) func(Either[E, A]) Either[E, B] {
|
||||||
|
return Map[E, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *eitherMonad[E, A, B]) Chain(f func(A) Either[E, B]) func(Either[E, A]) Either[E, B] {
|
||||||
|
return Chain[E, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *eitherMonad[E, A, B]) Ap(fa Either[E, A]) func(Either[E, func(A) B]) Either[E, B] {
|
||||||
|
return Ap[B, E, A](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monad implements the monadic operations for [Either]
|
||||||
|
func Monad[E, A, B any]() monad.Monad[A, B, Either[E, A], Either[E, B], Either[E, func(A) B]] {
|
||||||
|
return &eitherMonad[E, A, B]{}
|
||||||
|
}
|
@@ -19,38 +19,17 @@ import (
|
|||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
)
|
)
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
We need to pass the members of the applicative explicitly, because golang does neither support higher kinded types nor template methods on structs or interfaces
|
|
||||||
|
|
||||||
HKTRB = HKT<Either[B]>
|
|
||||||
HKTA = HKT<A>
|
|
||||||
HKTB = HKT<B>
|
|
||||||
*/
|
|
||||||
func traverse[E, A, B, HKTB, HKTRB any](
|
|
||||||
mof func(Either[E, B]) HKTRB,
|
|
||||||
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
|
|
||||||
) func(Either[E, A], func(A) HKTB) HKTRB {
|
|
||||||
|
|
||||||
left := F.Flow2(Left[B, E], mof)
|
|
||||||
right := mmap(Right[E, B])
|
|
||||||
|
|
||||||
return func(ta Either[E, A], f func(A) HKTB) HKTRB {
|
|
||||||
return MonadFold(ta,
|
|
||||||
left,
|
|
||||||
F.Flow2(f, right),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
|
// Traverse converts an [Either] of some higher kinded type into the higher kinded type of an [Either]
|
||||||
func Traverse[A, E, B, HKTB, HKTRB any](
|
func Traverse[A, E, B, HKTB, HKTRB any](
|
||||||
mof func(Either[E, B]) HKTRB,
|
mof func(Either[E, B]) HKTRB,
|
||||||
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
|
mmap func(func(B) Either[E, B]) func(HKTB) HKTRB,
|
||||||
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
|
) func(func(A) HKTB) func(Either[E, A]) HKTRB {
|
||||||
delegate := traverse[E, A, B](mof, mmap)
|
|
||||||
|
left := F.Flow2(Left[B, E], mof)
|
||||||
|
right := mmap(Right[E, B])
|
||||||
|
|
||||||
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
|
return func(f func(A) HKTB) func(Either[E, A]) HKTRB {
|
||||||
return F.Bind2nd(delegate, f)
|
return Fold(left, F.Flow2(f, right))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
8
eq/eq.go
8
eq/eq.go
@@ -27,20 +27,20 @@ type eq[T any] struct {
|
|||||||
c func(x, y T) bool
|
c func(x, y T) bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self eq[T]) Equals(x, y T) bool {
|
func (e eq[T]) Equals(x, y T) bool {
|
||||||
return self.c(x, y)
|
return e.c(x, y)
|
||||||
}
|
}
|
||||||
|
|
||||||
func strictEq[A comparable](a, b A) bool {
|
func strictEq[A comparable](a, b A) bool {
|
||||||
return a == b
|
return a == b
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[T comparable]() Eq[T] {
|
func FromStrictEquals[T comparable]() Eq[T] {
|
||||||
return FromEquals(strictEq[T])
|
return FromEquals(strictEq[T])
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromEquals constructs an `Eq` from the comparison function
|
// FromEquals constructs an [EQ.Eq] from the comparison function
|
||||||
func FromEquals[T any](c func(x, y T) bool) Eq[T] {
|
func FromEquals[T any](c func(x, y T) bool) Eq[T] {
|
||||||
return eq[T]{c: c}
|
return eq[T]{c: c}
|
||||||
}
|
}
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-12-18 09:38:59.1616876 +0100 CET m=+0.008641801
|
// 2024-01-31 21:45:01.6437619 +0100 CET m=+0.032758901
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
|
@@ -25,13 +25,13 @@ func Memoize[K comparable, T any](f func(K) T) func(K) T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
// ContramapMemoize converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func ContramapMemoize[A any, K comparable, T any](kf func(A) K) func(func(A) T) func(A) T {
|
func ContramapMemoize[T, A any, K comparable](kf func(A) K) func(func(A) T) func(A) T {
|
||||||
return G.ContramapMemoize[func(A) T](kf)
|
return G.ContramapMemoize[func(A) T](kf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
// CacheCallback converts a unary function into a unary function that caches the value depending on the parameter
|
||||||
func CacheCallback[
|
func CacheCallback[
|
||||||
A any, K comparable, T any](kf func(A) K, getOrCreate func(K, func() func() T) func() T) func(func(A) T) func(A) T {
|
T, A any, K comparable](kf func(A) K, getOrCreate func(K, func() func() T) func() T) func(func(A) T) func(A) T {
|
||||||
return G.CacheCallback[func(func(A) T) func(A) T](kf, getOrCreate)
|
return G.CacheCallback[func(func(A) T) func(A) T](kf, getOrCreate)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
252
function/gen.go
252
function/gen.go
@@ -1,6 +1,6 @@
|
|||||||
// Code generated by go generate; DO NOT EDIT.
|
// Code generated by go generate; DO NOT EDIT.
|
||||||
// This file was generated by robots at
|
// This file was generated by robots at
|
||||||
// 2023-12-18 09:38:51.4946446 +0100 CET m=+0.008838401
|
// 2024-01-31 21:44:55.7538323 +0100 CET m=+0.013067701
|
||||||
|
|
||||||
package function
|
package function
|
||||||
|
|
||||||
@@ -34,8 +34,7 @@ func Unsliced0[F ~func([]T) R, T, R any](f F) func() R {
|
|||||||
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
// Pipe1 takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
|
func Pipe1[F1 ~func(T0) T1, T0, T1 any](t0 T0, f1 F1) T1 {
|
||||||
t1 := f1(t0)
|
return f1(t0)
|
||||||
return t1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow1 creates a function that takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
// Flow1 creates a function that takes an initial value t0 and successively applies 1 functions where the input of a function is the return value of the previous function
|
||||||
@@ -93,9 +92,7 @@ func Unsliced1[F ~func([]T) R, T, R any](f F) func(T) R {
|
|||||||
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
// Pipe2 takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
|
func Pipe2[F1 ~func(T0) T1, F2 ~func(T1) T2, T0, T1, T2 any](t0 T0, f1 F1, f2 F2) T2 {
|
||||||
t1 := f1(t0)
|
return f2(f1(t0))
|
||||||
t2 := f2(t1)
|
|
||||||
return t2
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow2 creates a function that takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
// Flow2 creates a function that takes an initial value t0 and successively applies 2 functions where the input of a function is the return value of the previous function
|
||||||
@@ -155,10 +152,7 @@ func Unsliced2[F ~func([]T) R, T, R any](f F) func(T, T) R {
|
|||||||
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
// Pipe3 takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
|
func Pipe3[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, T0, T1, T2, T3 any](t0 T0, f1 F1, f2 F2, f3 F3) T3 {
|
||||||
t1 := f1(t0)
|
return f3(f2(f1(t0)))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
return t3
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow3 creates a function that takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
// Flow3 creates a function that takes an initial value t0 and successively applies 3 functions where the input of a function is the return value of the previous function
|
||||||
@@ -220,11 +214,7 @@ func Unsliced3[F ~func([]T) R, T, R any](f F) func(T, T, T) R {
|
|||||||
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
// Pipe4 takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
|
func Pipe4[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, T0, T1, T2, T3, T4 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4) T4 {
|
||||||
t1 := f1(t0)
|
return f4(f3(f2(f1(t0))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
return t4
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow4 creates a function that takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
// Flow4 creates a function that takes an initial value t0 and successively applies 4 functions where the input of a function is the return value of the previous function
|
||||||
@@ -288,12 +278,7 @@ func Unsliced4[F ~func([]T) R, T, R any](f F) func(T, T, T, T) R {
|
|||||||
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
// Pipe5 takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
|
func Pipe5[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, T0, T1, T2, T3, T4, T5 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) T5 {
|
||||||
t1 := f1(t0)
|
return f5(f4(f3(f2(f1(t0)))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
return t5
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow5 creates a function that takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
// Flow5 creates a function that takes an initial value t0 and successively applies 5 functions where the input of a function is the return value of the previous function
|
||||||
@@ -359,13 +344,7 @@ func Unsliced5[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T) R {
|
|||||||
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
// Pipe6 takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
|
func Pipe6[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, T0, T1, T2, T3, T4, T5, T6 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) T6 {
|
||||||
t1 := f1(t0)
|
return f6(f5(f4(f3(f2(f1(t0))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
return t6
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow6 creates a function that takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
// Flow6 creates a function that takes an initial value t0 and successively applies 6 functions where the input of a function is the return value of the previous function
|
||||||
@@ -433,14 +412,7 @@ func Unsliced6[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T) R {
|
|||||||
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
// Pipe7 takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
|
func Pipe7[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, T0, T1, T2, T3, T4, T5, T6, T7 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) T7 {
|
||||||
t1 := f1(t0)
|
return f7(f6(f5(f4(f3(f2(f1(t0)))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
return t7
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow7 creates a function that takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
// Flow7 creates a function that takes an initial value t0 and successively applies 7 functions where the input of a function is the return value of the previous function
|
||||||
@@ -510,15 +482,7 @@ func Unsliced7[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T) R {
|
|||||||
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
// Pipe8 takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
|
func Pipe8[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, T0, T1, T2, T3, T4, T5, T6, T7, T8 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) T8 {
|
||||||
t1 := f1(t0)
|
return f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
return t8
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow8 creates a function that takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
// Flow8 creates a function that takes an initial value t0 and successively applies 8 functions where the input of a function is the return value of the previous function
|
||||||
@@ -590,16 +554,7 @@ func Unsliced8[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T) R {
|
|||||||
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
// Pipe9 takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
|
func Pipe9[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) T9 {
|
||||||
t1 := f1(t0)
|
return f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
return t9
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow9 creates a function that takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
// Flow9 creates a function that takes an initial value t0 and successively applies 9 functions where the input of a function is the return value of the previous function
|
||||||
@@ -673,17 +628,7 @@ func Unsliced9[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T) R
|
|||||||
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
// Pipe10 takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
|
func Pipe10[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) T10 {
|
||||||
t1 := f1(t0)
|
return f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
return t10
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow10 creates a function that takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
// Flow10 creates a function that takes an initial value t0 and successively applies 10 functions where the input of a function is the return value of the previous function
|
||||||
@@ -759,18 +704,7 @@ func Unsliced10[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
// Pipe11 takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
|
func Pipe11[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11) T11 {
|
||||||
t1 := f1(t0)
|
return f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
return t11
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow11 creates a function that takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
// Flow11 creates a function that takes an initial value t0 and successively applies 11 functions where the input of a function is the return value of the previous function
|
||||||
@@ -848,19 +782,7 @@ func Unsliced11[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
// Pipe12 takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
|
func Pipe12[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12) T12 {
|
||||||
t1 := f1(t0)
|
return f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
return t12
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow12 creates a function that takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
// Flow12 creates a function that takes an initial value t0 and successively applies 12 functions where the input of a function is the return value of the previous function
|
||||||
@@ -940,20 +862,7 @@ func Unsliced12[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
// Pipe13 takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
|
func Pipe13[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13) T13 {
|
||||||
t1 := f1(t0)
|
return f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
return t13
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow13 creates a function that takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
// Flow13 creates a function that takes an initial value t0 and successively applies 13 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1035,21 +944,7 @@ func Unsliced13[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
// Pipe14 takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
|
func Pipe14[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14) T14 {
|
||||||
t1 := f1(t0)
|
return f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
return t14
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow14 creates a function that takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
// Flow14 creates a function that takes an initial value t0 and successively applies 14 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1133,22 +1028,7 @@ func Unsliced14[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
// Pipe15 takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
|
func Pipe15[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15) T15 {
|
||||||
t1 := f1(t0)
|
return f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
return t15
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow15 creates a function that takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
// Flow15 creates a function that takes an initial value t0 and successively applies 15 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1234,23 +1114,7 @@ func Unsliced15[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
// Pipe16 takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
|
func Pipe16[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16) T16 {
|
||||||
t1 := f1(t0)
|
return f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
t16 := f16(t15)
|
|
||||||
return t16
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow16 creates a function that takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
// Flow16 creates a function that takes an initial value t0 and successively applies 16 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1338,24 +1202,7 @@ func Unsliced16[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
// Pipe17 takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
|
func Pipe17[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17) T17 {
|
||||||
t1 := f1(t0)
|
return f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
t16 := f16(t15)
|
|
||||||
t17 := f17(t16)
|
|
||||||
return t17
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow17 creates a function that takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
// Flow17 creates a function that takes an initial value t0 and successively applies 17 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1445,25 +1292,7 @@ func Unsliced17[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
// Pipe18 takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
|
func Pipe18[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18) T18 {
|
||||||
t1 := f1(t0)
|
return f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
t16 := f16(t15)
|
|
||||||
t17 := f17(t16)
|
|
||||||
t18 := f18(t17)
|
|
||||||
return t18
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow18 creates a function that takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
// Flow18 creates a function that takes an initial value t0 and successively applies 18 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1555,26 +1384,7 @@ func Unsliced18[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
// Pipe19 takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
|
func Pipe19[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19) T19 {
|
||||||
t1 := f1(t0)
|
return f19(f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0)))))))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
t16 := f16(t15)
|
|
||||||
t17 := f17(t16)
|
|
||||||
t18 := f18(t17)
|
|
||||||
t19 := f19(t18)
|
|
||||||
return t19
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow19 creates a function that takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
// Flow19 creates a function that takes an initial value t0 and successively applies 19 functions where the input of a function is the return value of the previous function
|
||||||
@@ -1668,27 +1478,7 @@ func Unsliced19[F ~func([]T) R, T, R any](f F) func(T, T, T, T, T, T, T, T, T, T
|
|||||||
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
// Pipe20 takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
||||||
// The final return value is the result of the last function application
|
// The final return value is the result of the last function application
|
||||||
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
|
func Pipe20[F1 ~func(T0) T1, F2 ~func(T1) T2, F3 ~func(T2) T3, F4 ~func(T3) T4, F5 ~func(T4) T5, F6 ~func(T5) T6, F7 ~func(T6) T7, F8 ~func(T7) T8, F9 ~func(T8) T9, F10 ~func(T9) T10, F11 ~func(T10) T11, F12 ~func(T11) T12, F13 ~func(T12) T13, F14 ~func(T13) T14, F15 ~func(T14) T15, F16 ~func(T15) T16, F17 ~func(T16) T17, F18 ~func(T17) T18, F19 ~func(T18) T19, F20 ~func(T19) T20, T0, T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12, T13, T14, T15, T16, T17, T18, T19, T20 any](t0 T0, f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10, f11 F11, f12 F12, f13 F13, f14 F14, f15 F15, f16 F16, f17 F17, f18 F18, f19 F19, f20 F20) T20 {
|
||||||
t1 := f1(t0)
|
return f20(f19(f18(f17(f16(f15(f14(f13(f12(f11(f10(f9(f8(f7(f6(f5(f4(f3(f2(f1(t0))))))))))))))))))))
|
||||||
t2 := f2(t1)
|
|
||||||
t3 := f3(t2)
|
|
||||||
t4 := f4(t3)
|
|
||||||
t5 := f5(t4)
|
|
||||||
t6 := f6(t5)
|
|
||||||
t7 := f7(t6)
|
|
||||||
t8 := f8(t7)
|
|
||||||
t9 := f9(t8)
|
|
||||||
t10 := f10(t9)
|
|
||||||
t11 := f11(t10)
|
|
||||||
t12 := f12(t11)
|
|
||||||
t13 := f13(t12)
|
|
||||||
t14 := f14(t13)
|
|
||||||
t15 := f15(t14)
|
|
||||||
t16 := f16(t15)
|
|
||||||
t17 := f17(t16)
|
|
||||||
t18 := f18(t17)
|
|
||||||
t19 := f19(t18)
|
|
||||||
t20 := f20(t19)
|
|
||||||
return t20
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flow20 creates a function that takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
// Flow20 creates a function that takes an initial value t0 and successively applies 20 functions where the input of a function is the return value of the previous function
|
||||||
|
@@ -16,9 +16,14 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha256"
|
||||||
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
B "github.com/IBM/fp-go/bytes"
|
||||||
E "github.com/IBM/fp-go/either"
|
E "github.com/IBM/fp-go/either"
|
||||||
ENDO "github.com/IBM/fp-go/endomorphism"
|
ENDO "github.com/IBM/fp-go/endomorphism"
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
@@ -29,6 +34,7 @@ import (
|
|||||||
LZ "github.com/IBM/fp-go/lazy"
|
LZ "github.com/IBM/fp-go/lazy"
|
||||||
L "github.com/IBM/fp-go/optics/lens"
|
L "github.com/IBM/fp-go/optics/lens"
|
||||||
O "github.com/IBM/fp-go/option"
|
O "github.com/IBM/fp-go/option"
|
||||||
|
R "github.com/IBM/fp-go/record"
|
||||||
S "github.com/IBM/fp-go/string"
|
S "github.com/IBM/fp-go/string"
|
||||||
T "github.com/IBM/fp-go/tuple"
|
T "github.com/IBM/fp-go/tuple"
|
||||||
)
|
)
|
||||||
@@ -56,7 +62,11 @@ var (
|
|||||||
Monoid = ENDO.Monoid[*Builder]()
|
Monoid = ENDO.Monoid[*Builder]()
|
||||||
|
|
||||||
// Url is a [L.Lens] for the URL
|
// Url is a [L.Lens] for the URL
|
||||||
Url = L.MakeLensRef((*Builder).GetUrl, (*Builder).SetUrl)
|
//
|
||||||
|
// Deprecated: use [URL] instead
|
||||||
|
Url = L.MakeLensRef((*Builder).GetURL, (*Builder).SetURL)
|
||||||
|
// URL is a [L.Lens] for the URL
|
||||||
|
URL = L.MakeLensRef((*Builder).GetURL, (*Builder).SetURL)
|
||||||
// Method is a [L.Lens] for the HTTP method
|
// Method is a [L.Lens] for the HTTP method
|
||||||
Method = L.MakeLensRef((*Builder).GetMethod, (*Builder).SetMethod)
|
Method = L.MakeLensRef((*Builder).GetMethod, (*Builder).SetMethod)
|
||||||
// Body is a [L.Lens] for the request body
|
// Body is a [L.Lens] for the request body
|
||||||
@@ -76,15 +86,19 @@ var (
|
|||||||
noBody = O.None[E.Either[error, []byte]]()
|
noBody = O.None[E.Either[error, []byte]]()
|
||||||
noQueryArg = O.None[string]()
|
noQueryArg = O.None[string]()
|
||||||
|
|
||||||
parseUrl = E.Eitherize1(url.Parse)
|
parseURL = E.Eitherize1(url.Parse)
|
||||||
parseQuery = E.Eitherize1(url.ParseQuery)
|
parseQuery = E.Eitherize1(url.ParseQuery)
|
||||||
|
|
||||||
// WithQuery creates a [Endomorphism] for a complete set of query parameters
|
// WithQuery creates a [Endomorphism] for a complete set of query parameters
|
||||||
WithQuery = Query.Set
|
WithQuery = Query.Set
|
||||||
// WithMethod creates a [Endomorphism] for a certain method
|
// WithMethod creates a [Endomorphism] for a certain method
|
||||||
WithMethod = Method.Set
|
WithMethod = Method.Set
|
||||||
// WithUrl creates a [Endomorphism] for a certain method
|
// WithUrl creates a [Endomorphism] for the URL
|
||||||
WithUrl = Url.Set
|
//
|
||||||
|
// Deprecated: use [WithURL] instead
|
||||||
|
WithUrl = URL.Set
|
||||||
|
// WithURL creates a [Endomorphism] for the URL
|
||||||
|
WithURL = URL.Set
|
||||||
// WithHeaders creates a [Endomorphism] for a set of headers
|
// WithHeaders creates a [Endomorphism] for a set of headers
|
||||||
WithHeaders = Headers.Set
|
WithHeaders = Headers.Set
|
||||||
// WithBody creates a [Endomorphism] for a request body
|
// WithBody creates a [Endomorphism] for a request body
|
||||||
@@ -130,6 +144,9 @@ var (
|
|||||||
WithBytes,
|
WithBytes,
|
||||||
ENDO.Chain(WithContentType(C.FormEncoded)),
|
ENDO.Chain(WithContentType(C.FormEncoded)),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// bodyAsBytes returns a []byte with a fallback to the empty array
|
||||||
|
bodyAsBytes = O.Fold(B.Empty, E.Fold(F.Ignore1of1[error](B.Empty), F.Identity[[]byte]))
|
||||||
)
|
)
|
||||||
|
|
||||||
func setRawQuery(u *url.URL, raw string) *url.URL {
|
func setRawQuery(u *url.URL, raw string) *url.URL {
|
||||||
@@ -148,12 +165,19 @@ func (builder *Builder) clone() *Builder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetTargetUrl constructs a full URL with query parameters on top of the provided URL string
|
// GetTargetUrl constructs a full URL with query parameters on top of the provided URL string
|
||||||
|
//
|
||||||
|
// Deprecated: use [GetTargetURL] instead
|
||||||
func (builder *Builder) GetTargetUrl() E.Either[error, string] {
|
func (builder *Builder) GetTargetUrl() E.Either[error, string] {
|
||||||
|
return builder.GetTargetURL()
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTargetURL constructs a full URL with query parameters on top of the provided URL string
|
||||||
|
func (builder *Builder) GetTargetURL() E.Either[error, string] {
|
||||||
// construct the final URL
|
// construct the final URL
|
||||||
return F.Pipe3(
|
return F.Pipe3(
|
||||||
builder,
|
builder,
|
||||||
Url.Get,
|
Url.Get,
|
||||||
parseUrl,
|
parseURL,
|
||||||
E.Chain(F.Flow4(
|
E.Chain(F.Flow4(
|
||||||
T.Replicate2[*url.URL],
|
T.Replicate2[*url.URL],
|
||||||
T.Map2(
|
T.Map2(
|
||||||
@@ -176,10 +200,15 @@ func (builder *Builder) GetTargetUrl() E.Either[error, string] {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use [GetURL] instead
|
||||||
func (builder *Builder) GetUrl() string {
|
func (builder *Builder) GetUrl() string {
|
||||||
return builder.url
|
return builder.url
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) GetURL() string {
|
||||||
|
return builder.url
|
||||||
|
}
|
||||||
|
|
||||||
func (builder *Builder) GetMethod() string {
|
func (builder *Builder) GetMethod() string {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
builder.method,
|
builder.method,
|
||||||
@@ -209,11 +238,17 @@ func (builder *Builder) SetMethod(method string) *Builder {
|
|||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Deprecated: use [SetURL] instead
|
||||||
func (builder *Builder) SetUrl(url string) *Builder {
|
func (builder *Builder) SetUrl(url string) *Builder {
|
||||||
builder.url = url
|
builder.url = url
|
||||||
return builder
|
return builder
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (builder *Builder) SetURL(url string) *Builder {
|
||||||
|
builder.url = url
|
||||||
|
return builder
|
||||||
|
}
|
||||||
|
|
||||||
func (builder *Builder) SetHeaders(headers http.Header) *Builder {
|
func (builder *Builder) SetHeaders(headers http.Header) *Builder {
|
||||||
builder.headers = headers
|
builder.headers = headers
|
||||||
return builder
|
return builder
|
||||||
@@ -246,6 +281,11 @@ func (builder *Builder) GetHeaderValues(name string) []string {
|
|||||||
return builder.headers.Values(name)
|
return builder.headers.Values(name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetHash returns a hash value for the builder that can be used as a cache key
|
||||||
|
func (builder *Builder) GetHash() string {
|
||||||
|
return MakeHash(builder)
|
||||||
|
}
|
||||||
|
|
||||||
// Header returns a [L.Lens] for a single header
|
// Header returns a [L.Lens] for a single header
|
||||||
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
func Header(name string) L.Lens[*Builder, O.Option[string]] {
|
||||||
get := getHeader(name)
|
get := getHeader(name)
|
||||||
@@ -278,14 +318,21 @@ func WithoutHeader(name string) Endomorphism {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WithJson creates a [Endomorphism] to send JSON payload
|
// WithJson creates a [Endomorphism] to send JSON payload
|
||||||
|
//
|
||||||
|
// Deprecated: use [WithJSON] instead
|
||||||
func WithJson[T any](data T) Endomorphism {
|
func WithJson[T any](data T) Endomorphism {
|
||||||
|
return WithJSON[T](data)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithJSON creates a [Endomorphism] to send JSON payload
|
||||||
|
func WithJSON[T any](data T) Endomorphism {
|
||||||
return Monoid.Concat(
|
return Monoid.Concat(
|
||||||
F.Pipe2(
|
F.Pipe2(
|
||||||
data,
|
data,
|
||||||
J.Marshal[T],
|
J.Marshal[T],
|
||||||
WithBody,
|
WithBody,
|
||||||
),
|
),
|
||||||
WithContentType(C.Json),
|
WithContentType(C.JSON),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -309,3 +356,32 @@ func WithQueryArg(name string) func(value string) Endomorphism {
|
|||||||
func WithoutQueryArg(name string) Endomorphism {
|
func WithoutQueryArg(name string) Endomorphism {
|
||||||
return QueryArg(name).Set(noQueryArg)
|
return QueryArg(name).Set(noQueryArg)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func hashWriteValue(buf *bytes.Buffer, value string) *bytes.Buffer {
|
||||||
|
buf.WriteString(value)
|
||||||
|
return buf
|
||||||
|
}
|
||||||
|
|
||||||
|
func hashWriteQuery(name string, buf *bytes.Buffer, values []string) *bytes.Buffer {
|
||||||
|
buf.WriteString(name)
|
||||||
|
return A.Reduce(hashWriteValue, buf)(values)
|
||||||
|
}
|
||||||
|
|
||||||
|
func makeBytes(b *Builder) []byte {
|
||||||
|
var buf bytes.Buffer
|
||||||
|
|
||||||
|
buf.WriteString(b.GetMethod())
|
||||||
|
buf.WriteString(b.GetURL())
|
||||||
|
b.GetHeaders().Write(&buf) // #nosec: G104
|
||||||
|
|
||||||
|
R.ReduceOrdWithIndex[[]string, *bytes.Buffer](S.Ord)(hashWriteQuery, &buf)(b.GetQuery())
|
||||||
|
|
||||||
|
buf.Write(bodyAsBytes(b.GetBody()))
|
||||||
|
|
||||||
|
return buf.Bytes()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MakeHash converts a [Builder] into a hash string, convenient to use as a cache key
|
||||||
|
func MakeHash(b *Builder) string {
|
||||||
|
return fmt.Sprintf("%x", sha256.Sum256(makeBytes(b)))
|
||||||
|
}
|
||||||
|
@@ -16,6 +16,7 @@
|
|||||||
package builder
|
package builder
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
@@ -34,7 +35,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
|
|
||||||
b1 := F.Pipe1(
|
b1 := F.Pipe1(
|
||||||
Default,
|
Default,
|
||||||
withContentType(C.Json),
|
withContentType(C.JSON),
|
||||||
)
|
)
|
||||||
|
|
||||||
b2 := F.Pipe1(
|
b2 := F.Pipe1(
|
||||||
@@ -48,7 +49,7 @@ func TestBuilder(t *testing.T) {
|
|||||||
)
|
)
|
||||||
|
|
||||||
assert.Equal(t, O.None[string](), Default.GetHeader(name))
|
assert.Equal(t, O.None[string](), Default.GetHeader(name))
|
||||||
assert.Equal(t, O.Of(C.Json), b1.GetHeader(name))
|
assert.Equal(t, O.Of(C.JSON), b1.GetHeader(name))
|
||||||
assert.Equal(t, O.Of(C.TextPlain), b2.GetHeader(name))
|
assert.Equal(t, O.Of(C.TextPlain), b2.GetHeader(name))
|
||||||
assert.Equal(t, O.None[string](), b3.GetHeader(name))
|
assert.Equal(t, O.None[string](), b3.GetHeader(name))
|
||||||
}
|
}
|
||||||
@@ -66,3 +67,27 @@ func TestWithFormData(t *testing.T) {
|
|||||||
|
|
||||||
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
assert.Equal(t, C.FormEncoded, Headers.Get(res).Get(H.ContentType))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestHash(t *testing.T) {
|
||||||
|
|
||||||
|
b1 := F.Pipe4(
|
||||||
|
Default,
|
||||||
|
WithContentType(C.JSON),
|
||||||
|
WithHeader(H.Accept)(C.JSON),
|
||||||
|
WithURL("http://www.example.com"),
|
||||||
|
WithJSON(map[string]string{"a": "b"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
b2 := F.Pipe4(
|
||||||
|
Default,
|
||||||
|
WithURL("http://www.example.com"),
|
||||||
|
WithHeader(H.Accept)(C.JSON),
|
||||||
|
WithContentType(C.JSON),
|
||||||
|
WithJSON(map[string]string{"a": "b"}),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, MakeHash(b1), MakeHash(b2))
|
||||||
|
assert.NotEqual(t, MakeHash(Default), MakeHash(b2))
|
||||||
|
|
||||||
|
fmt.Println(MakeHash(b1))
|
||||||
|
}
|
||||||
|
@@ -17,6 +17,7 @@ package content
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
TextPlain = "text/plain"
|
TextPlain = "text/plain"
|
||||||
Json = "application/json"
|
JSON = "application/json"
|
||||||
|
Json = JSON // Deprecated: use [JSON] instead
|
||||||
FormEncoded = "application/x-www-form-urlencoded"
|
FormEncoded = "application/x-www-form-urlencoded"
|
||||||
)
|
)
|
||||||
|
@@ -39,7 +39,7 @@ var (
|
|||||||
|
|
||||||
noField = O.None[string]()
|
noField = O.None[string]()
|
||||||
|
|
||||||
// FormMonoid is the [M.Monoid] for the [Endomorphism]
|
// Monoid is the [M.Monoid] for the [Endomorphism]
|
||||||
Monoid = ENDO.Monoid[url.Values]()
|
Monoid = ENDO.Monoid[url.Values]()
|
||||||
|
|
||||||
// ValuesMonoid is a [M.Monoid] to concatenate [url.Values] maps
|
// ValuesMonoid is a [M.Monoid] to concatenate [url.Values] maps
|
||||||
|
@@ -20,6 +20,7 @@ import (
|
|||||||
"io"
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
H "net/http"
|
H "net/http"
|
||||||
|
"net/url"
|
||||||
"regexp"
|
"regexp"
|
||||||
|
|
||||||
A "github.com/IBM/fp-go/array"
|
A "github.com/IBM/fp-go/array"
|
||||||
@@ -33,33 +34,44 @@ import (
|
|||||||
|
|
||||||
type (
|
type (
|
||||||
ParsedMediaType = T.Tuple2[string, map[string]string]
|
ParsedMediaType = T.Tuple2[string, map[string]string]
|
||||||
|
|
||||||
|
HttpError struct {
|
||||||
|
statusCode int
|
||||||
|
headers H.Header
|
||||||
|
body []byte
|
||||||
|
url *url.URL
|
||||||
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// mime type to check if a media type matches
|
// mime type to check if a media type matches
|
||||||
reJsonMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`)
|
reJSONMimeType = regexp.MustCompile(`application/(?:\w+\+)?json`)
|
||||||
// ValidateResponse validates an HTTP response and returns an [E.Either] if the response is not a success
|
// ValidateResponse validates an HTTP response and returns an [E.Either] if the response is not a success
|
||||||
ValidateResponse = E.FromPredicate(isValidStatus, StatusCodeError)
|
ValidateResponse = E.FromPredicate(isValidStatus, StatusCodeError)
|
||||||
// alidateJsonContentTypeString parses a content type a validates that it is valid JSON
|
// alidateJsonContentTypeString parses a content type a validates that it is valid JSON
|
||||||
validateJsonContentTypeString = F.Flow2(
|
validateJSONContentTypeString = F.Flow2(
|
||||||
ParseMediaType,
|
ParseMediaType,
|
||||||
E.ChainFirst(F.Flow2(
|
E.ChainFirst(F.Flow2(
|
||||||
T.First[string, map[string]string],
|
T.First[string, map[string]string],
|
||||||
E.FromPredicate(reJsonMimeType.MatchString, func(mimeType string) error {
|
E.FromPredicate(reJSONMimeType.MatchString, func(mimeType string) error {
|
||||||
return fmt.Errorf("mimetype [%s] is not a valid JSON content type", mimeType)
|
return fmt.Errorf("mimetype [%s] is not a valid JSON content type", mimeType)
|
||||||
}),
|
}),
|
||||||
)),
|
)),
|
||||||
)
|
)
|
||||||
// ValidateJsonResponse checks if an HTTP response is a valid JSON response
|
// ValidateJSONResponse checks if an HTTP response is a valid JSON response
|
||||||
ValidateJsonResponse = F.Flow2(
|
ValidateJSONResponse = F.Flow2(
|
||||||
E.Of[error, *H.Response],
|
E.Of[error, *H.Response],
|
||||||
E.ChainFirst(F.Flow5(
|
E.ChainFirst(F.Flow5(
|
||||||
GetHeader,
|
GetHeader,
|
||||||
R.Lookup[H.Header](HeaderContentType),
|
R.Lookup[H.Header](HeaderContentType),
|
||||||
O.Chain(A.First[string]),
|
O.Chain(A.First[string]),
|
||||||
E.FromOption[string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
|
E.FromOption[string](errors.OnNone("unable to access the [%s] header", HeaderContentType)),
|
||||||
E.ChainFirst(validateJsonContentTypeString),
|
E.ChainFirst(validateJSONContentTypeString),
|
||||||
)))
|
)))
|
||||||
|
// ValidateJsonResponse checks if an HTTP response is a valid JSON response
|
||||||
|
//
|
||||||
|
// Deprecated: use [ValidateJSONResponse] instead
|
||||||
|
ValidateJsonResponse = ValidateJSONResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
@@ -72,6 +84,31 @@ func ParseMediaType(mediaType string) E.Either[error, ParsedMediaType] {
|
|||||||
return E.TryCatchError(T.MakeTuple2(m, p), err)
|
return E.TryCatchError(T.MakeTuple2(m, p), err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Error fulfills the error interface
|
||||||
|
func (r *HttpError) Error() string {
|
||||||
|
return fmt.Sprintf("invalid status code [%d] when accessing URL [%s]", r.statusCode, r.url)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpError) String() string {
|
||||||
|
return r.Error()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpError) StatusCode() int {
|
||||||
|
return r.statusCode
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpError) Headers() H.Header {
|
||||||
|
return r.headers
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpError) URL() *url.URL {
|
||||||
|
return r.url
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *HttpError) Body() []byte {
|
||||||
|
return r.body
|
||||||
|
}
|
||||||
|
|
||||||
func GetHeader(resp *H.Response) H.Header {
|
func GetHeader(resp *H.Response) H.Header {
|
||||||
return resp.Header
|
return resp.Header
|
||||||
}
|
}
|
||||||
@@ -84,6 +121,13 @@ func isValidStatus(resp *H.Response) bool {
|
|||||||
return resp.StatusCode >= H.StatusOK && resp.StatusCode < H.StatusMultipleChoices
|
return resp.StatusCode >= H.StatusOK && resp.StatusCode < H.StatusMultipleChoices
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StatusCodeError creates an instance of [HttpError] filled with information from the response
|
||||||
func StatusCodeError(resp *H.Response) error {
|
func StatusCodeError(resp *H.Response) error {
|
||||||
return fmt.Errorf("invalid status code [%d] when accessing URL [%s]", resp.StatusCode, resp.Request.URL)
|
// read the body
|
||||||
|
bodyRdr := GetBody(resp)
|
||||||
|
defer bodyRdr.Close()
|
||||||
|
// try to access body content
|
||||||
|
body, _ := io.ReadAll(bodyRdr)
|
||||||
|
// return an error with comprehensive information
|
||||||
|
return &HttpError{statusCode: resp.StatusCode, headers: GetHeader(resp).Clone(), body: body, url: resp.Request.URL}
|
||||||
}
|
}
|
||||||
|
@@ -39,7 +39,7 @@ func Error[A any](t *testing.T) func(E.Either[error, A]) bool {
|
|||||||
func TestValidateJsonContentTypeString(t *testing.T) {
|
func TestValidateJsonContentTypeString(t *testing.T) {
|
||||||
|
|
||||||
res := F.Pipe1(
|
res := F.Pipe1(
|
||||||
validateJsonContentTypeString(C.Json),
|
validateJSONContentTypeString(C.JSON),
|
||||||
NoError[ParsedMediaType](t),
|
NoError[ParsedMediaType](t),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -49,7 +49,7 @@ func TestValidateJsonContentTypeString(t *testing.T) {
|
|||||||
func TestValidateInvalidJsonContentTypeString(t *testing.T) {
|
func TestValidateInvalidJsonContentTypeString(t *testing.T) {
|
||||||
|
|
||||||
res := F.Pipe1(
|
res := F.Pipe1(
|
||||||
validateJsonContentTypeString("application/xml"),
|
validateJSONContentTypeString("application/xml"),
|
||||||
Error[ParsedMediaType](t),
|
Error[ParsedMediaType](t),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
89
identity/bind.go
Normal file
89
identity/bind.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// 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 identity
|
||||||
|
|
||||||
|
import (
|
||||||
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) S {
|
||||||
|
return empty
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(S1) S2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[S1, S2],
|
||||||
|
Map[T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(S1) S2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(S1) S2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(T) S1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa T,
|
||||||
|
) func(S1) S2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[S2, T],
|
||||||
|
Map[S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@@ -50,7 +50,11 @@ func MonadChainFirst[GAB ~func(A) B, A, B any](fa A, f GAB) A {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
|
func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A {
|
||||||
return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f)
|
return C.ChainFirst(
|
||||||
|
Chain[func(A) A, A, A],
|
||||||
|
Map[func(B) A, B, A],
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
|
func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
|
||||||
@@ -58,5 +62,5 @@ func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Flap[GAB ~func(A) B, B, A any](a A) func(GAB) B {
|
func Flap[GAB ~func(A) B, B, A any](a A) func(GAB) B {
|
||||||
return F.Bind2nd(MonadFlap[GAB, A, B], a)
|
return FC.Flap(Map[func(GAB) B, GAB, B], a)
|
||||||
}
|
}
|
||||||
|
43
identity/monad.go
Normal file
43
identity/monad.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2024 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 identity
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
)
|
||||||
|
|
||||||
|
type identityMonad[A, B any] struct{}
|
||||||
|
|
||||||
|
func (o *identityMonad[A, B]) Of(a A) A {
|
||||||
|
return Of[A](a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *identityMonad[A, B]) Map(f func(A) B) func(A) B {
|
||||||
|
return Map[A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *identityMonad[A, B]) Chain(f func(A) B) func(A) B {
|
||||||
|
return Chain[A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *identityMonad[A, B]) Ap(fa A) func(func(A) B) B {
|
||||||
|
return Ap[B, A](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monad implements the monadic operations for [Option]
|
||||||
|
func Monad[A, B any]() monad.Monad[A, B, A, B, func(A) B] {
|
||||||
|
return &identityMonad[A, B]{}
|
||||||
|
}
|
@@ -34,6 +34,9 @@ func AssertIdentity[HKTA, HKTAA, A any](t *testing.T,
|
|||||||
|
|
||||||
fap func(HKTAA, HKTA) HKTA,
|
fap func(HKTAA, HKTA) HKTA,
|
||||||
) func(fa HKTA) bool {
|
) func(fa HKTA) bool {
|
||||||
|
// mark as test helper
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
return func(fa HKTA) bool {
|
return func(fa HKTA) bool {
|
||||||
|
|
||||||
left := fap(fof(F.Identity[A]), fa)
|
left := fap(fof(F.Identity[A]), fa)
|
||||||
@@ -57,6 +60,9 @@ func AssertHomomorphism[HKTA, HKTB, HKTAB, A, B any](t *testing.T,
|
|||||||
|
|
||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
) func(a A) bool {
|
) func(a A) bool {
|
||||||
|
// mark as test helper
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
return func(a A) bool {
|
return func(a A) bool {
|
||||||
|
|
||||||
left := fap(fofab(ab), fofa(a))
|
left := fap(fofab(ab), fofa(a))
|
||||||
@@ -73,7 +79,6 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
|
|||||||
eq E.Eq[HKTB],
|
eq E.Eq[HKTB],
|
||||||
|
|
||||||
fofa func(A) HKTA,
|
fofa func(A) HKTA,
|
||||||
fofb func(B) HKTB,
|
|
||||||
fofab func(func(A) B) HKTAB,
|
fofab func(func(A) B) HKTAB,
|
||||||
fofabb func(func(func(A) B) B) HKTABB,
|
fofabb func(func(func(A) B) B) HKTABB,
|
||||||
|
|
||||||
@@ -82,6 +87,9 @@ func AssertInterchange[HKTA, HKTB, HKTAB, HKTABB, A, B any](t *testing.T,
|
|||||||
|
|
||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
) func(a A) bool {
|
) func(a A) bool {
|
||||||
|
// mark as test helper
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
return func(a A) bool {
|
return func(a A) bool {
|
||||||
|
|
||||||
fab := fofab(ab)
|
fab := fofab(ab)
|
||||||
@@ -127,12 +135,15 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
|
|||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
bc func(B) C,
|
bc func(B) C,
|
||||||
) func(a A) bool {
|
) func(a A) bool {
|
||||||
|
// mark as test helper
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
// apply laws
|
// apply laws
|
||||||
apply := L.AssertLaws(t, eqa, eqc, fofab, fofbc, faa, fab, fac, fbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
|
apply := L.AssertLaws(t, eqa, eqc, fofab, fofbc, faa, fab, fac, fbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
|
||||||
// applicative laws
|
// applicative laws
|
||||||
identity := AssertIdentity(t, eqa, fofaa, fapaa)
|
identity := AssertIdentity(t, eqa, fofaa, fapaa)
|
||||||
homomorphism := AssertHomomorphism(t, eqb, fofa, fofb, fofab, fapab, ab)
|
homomorphism := AssertHomomorphism(t, eqb, fofa, fofb, fofab, fapab, ab)
|
||||||
interchange := AssertInterchange(t, eqb, fofa, fofb, fofab, fofabb, fapab, fapabb, ab)
|
interchange := AssertInterchange(t, eqb, fofa, fofab, fofabb, fapab, fapabb, ab)
|
||||||
|
|
||||||
return func(a A) bool {
|
return func(a A) bool {
|
||||||
fa := fofa(a)
|
fa := fofa(a)
|
||||||
|
26
internal/applicative/types.go
Normal file
26
internal/applicative/types.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package applicative
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/apply"
|
||||||
|
"github.com/IBM/fp-go/internal/pointed"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Applicative[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||||
|
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
|
||||||
|
pointed.Pointed[A, HKTA]
|
||||||
|
}
|
@@ -19,13 +19,6 @@ import (
|
|||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
)
|
)
|
||||||
|
|
||||||
// HKTFGA = HKT<F, HKT<G, A>>
|
|
||||||
// HKTFGB = HKT<F, HKT<G, B>>
|
|
||||||
// HKTFGAB = HKT<F, HKT<G, (a: A) => B>>
|
|
||||||
|
|
||||||
// HKTGA = HKT<G, A>
|
|
||||||
// HKTGB = HKT<G, B>
|
|
||||||
// HKTGAB = HKT<G, (a: A) => B>
|
|
||||||
func MonadAp[HKTGA, HKTGB, HKTGAB, HKTFGAB, HKTFGGAB, HKTFGA, HKTFGB any](
|
func MonadAp[HKTGA, HKTGB, HKTGAB, HKTFGAB, HKTFGGAB, HKTFGA, HKTFGB any](
|
||||||
fap func(HKTFGGAB, HKTFGA) HKTFGB,
|
fap func(HKTFGGAB, HKTFGA) HKTFGB,
|
||||||
fmap func(HKTFGAB, func(HKTGAB) func(HKTGA) HKTGB) HKTFGGAB,
|
fmap func(HKTFGAB, func(HKTGAB) func(HKTGA) HKTGB) HKTFGGAB,
|
||||||
@@ -37,6 +30,29 @@ func MonadAp[HKTGA, HKTGB, HKTGAB, HKTFGAB, HKTFGGAB, HKTFGA, HKTFGB any](
|
|||||||
return fap(fmap(fab, F.Bind1st(F.Bind1st[HKTGAB, HKTGA, HKTGB], gap)), fa)
|
return fap(fmap(fab, F.Bind1st(F.Bind1st[HKTGAB, HKTGA, HKTGB], gap)), fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Ap[HKTGA, HKTGB, HKTGAB, HKTFGAB, HKTFGGAB, HKTFGA, HKTFGB any](
|
||||||
|
fap func(HKTFGA) func(HKTFGGAB) HKTFGB,
|
||||||
|
fmap func(func(HKTGAB) func(HKTGA) HKTGB) func(HKTFGAB) HKTFGGAB,
|
||||||
|
gap func(HKTGA) func(HKTGAB) HKTGB,
|
||||||
|
|
||||||
|
fa HKTFGA) func(HKTFGAB) HKTFGB {
|
||||||
|
|
||||||
|
return F.Flow2(
|
||||||
|
fmap(F.Flip(gap)),
|
||||||
|
fap(fa),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// func Ap[HKTGA, HKTGB, HKTGAB, HKTFGAB, HKTFGGAB, HKTFGA, HKTFGB any](
|
||||||
|
// fap func(HKTFGA) func(HKTFGGAB) HKTFGB,
|
||||||
|
// fmap func(func(HKTGAB) func(HKTGA) HKTGB) func(HKTFGAB) HKTFGGAB,
|
||||||
|
// gap func(HKTGA) func(HKTGAB) HKTGB,
|
||||||
|
|
||||||
|
// fa HKTFGA) func(HKTFGAB) HKTFGB {
|
||||||
|
|
||||||
|
// return fap(fmap(F.Bind1st(F.Bind1st[HKTGAB, HKTGA, HKTGB], gap)), fa)
|
||||||
|
// }
|
||||||
|
|
||||||
// export function ap<F, G>(
|
// export function ap<F, G>(
|
||||||
// F: Apply<F>,
|
// F: Apply<F>,
|
||||||
// G: Apply<G>
|
// G: Apply<G>
|
||||||
@@ -107,3 +123,25 @@ func ApSecond[HKTGA, HKTGB, HKTGBB, A, B any](
|
|||||||
return MonadApSecond(fap, fmap, first, second)
|
return MonadApSecond(fap, fmap, first, second)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadApS[S1, S2, B, HKTBGBS2, HKTS1, HKTS2, HKTB any](
|
||||||
|
fap func(HKTBGBS2, HKTB) HKTS2,
|
||||||
|
fmap func(HKTS1, func(S1) func(B) S2) HKTBGBS2,
|
||||||
|
fa HKTS1,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
fb HKTB,
|
||||||
|
) HKTS2 {
|
||||||
|
return fap(fmap(fa, F.Flip(key)), fb)
|
||||||
|
}
|
||||||
|
|
||||||
|
func ApS[S1, S2, B, HKTBGBS2, HKTS1, HKTS2, HKTB any](
|
||||||
|
fap func(HKTB) func(HKTBGBS2) HKTS2,
|
||||||
|
fmap func(func(S1) func(B) S2) func(HKTS1) HKTBGBS2,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
fb HKTB,
|
||||||
|
) func(HKTS1) HKTS2 {
|
||||||
|
return F.Flow2(
|
||||||
|
fmap(F.Flip(key)),
|
||||||
|
fap(fb),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@@ -43,6 +43,7 @@ func AssertAssociativeComposition[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC
|
|||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
bc func(B) C,
|
bc func(B) C,
|
||||||
) func(fa HKTA) bool {
|
) func(fa HKTA) bool {
|
||||||
|
t.Helper()
|
||||||
return func(fa HKTA) bool {
|
return func(fa HKTA) bool {
|
||||||
|
|
||||||
fab := fofab(ab)
|
fab := fofab(ab)
|
||||||
@@ -86,6 +87,8 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
|
|||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
bc func(B) C,
|
bc func(B) C,
|
||||||
) func(fa HKTA) bool {
|
) func(fa HKTA) bool {
|
||||||
|
// mark as test helper
|
||||||
|
t.Helper()
|
||||||
// functor laws
|
// functor laws
|
||||||
functor := FCT.AssertLaws(t, eqa, eqc, faa, fab, fac, fbc, ab, bc)
|
functor := FCT.AssertLaws(t, eqa, eqc, faa, fab, fac, fbc, ab, bc)
|
||||||
// associative composition laws
|
// associative composition laws
|
||||||
|
25
internal/apply/types.go
Normal file
25
internal/apply/types.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// 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 apply
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Apply[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||||
|
functor.Functor[A, B, HKTA, HKTB]
|
||||||
|
Ap(HKTA) func(HKTFAB) HKTB
|
||||||
|
}
|
@@ -106,6 +106,12 @@ func MonadMap[GA ~[]A, GB ~[]B, A, B any](as GA, f func(a A) B) GB {
|
|||||||
return bs
|
return bs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[GA ~[]A, GB ~[]B, A, B any](f func(a A) B) func(GA) GB {
|
||||||
|
return func(as GA) GB {
|
||||||
|
return MonadMap[GA, GB](as, f)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(idx int, a A) B) GB {
|
func MonadMapWithIndex[GA ~[]A, GB ~[]B, A, B any](as GA, f func(idx int, a A) B) GB {
|
||||||
count := len(as)
|
count := len(as)
|
||||||
bs := make(GB, count)
|
bs := make(GB, count)
|
||||||
|
@@ -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 bindt
|
|
||||||
|
|
||||||
import (
|
|
||||||
F "github.com/IBM/fp-go/function"
|
|
||||||
I "github.com/IBM/fp-go/identity"
|
|
||||||
T "github.com/IBM/fp-go/tuple"
|
|
||||||
)
|
|
||||||
|
|
||||||
func Bind[SET ~func(B) func(S1) S2, FCT ~func(S1) HKTB, S1, S2, B, HKTS1, HKTS2, HKTB any](
|
|
||||||
mchain func(func(S1) HKTS2) func(HKTS1) HKTS2,
|
|
||||||
mmap func(func(B) S2) func(HKTB) HKTS2,
|
|
||||||
s SET,
|
|
||||||
f FCT,
|
|
||||||
) func(HKTS1) HKTS2 {
|
|
||||||
return mchain(F.Flow3(
|
|
||||||
T.Replicate2[S1],
|
|
||||||
T.Map2(F.Flow2(
|
|
||||||
I.Ap[S2, S1],
|
|
||||||
F.Flow2(
|
|
||||||
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s),
|
|
||||||
mmap,
|
|
||||||
)), f),
|
|
||||||
T.Tupled2(I.MonadAp[HKTS2, HKTB]),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
func BindTo[SET ~func(B) S2, S2, B, HKTS2, HKTB any](
|
|
||||||
mmap func(func(B) S2) func(HKTB) HKTS2,
|
|
||||||
s SET,
|
|
||||||
) func(HKTB) HKTS2 {
|
|
||||||
return mmap(s)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ApS[
|
|
||||||
SET ~func(B) func(S1) S2,
|
|
||||||
S1, S2, B, HKTS1S2, HKTS1, HKTS2, HKTB any,
|
|
||||||
](
|
|
||||||
ap func(HKTS1) func(HKTS1S2) HKTS2,
|
|
||||||
mmap func(func(B) func(S1) S2) func(HKTB) HKTS1S2,
|
|
||||||
s SET, fb HKTB) func(HKTS1) HKTS2 {
|
|
||||||
|
|
||||||
return F.Flow2(
|
|
||||||
ap,
|
|
||||||
I.Ap[HKTS2, HKTS1S2](mmap(s)(fb)),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Let[SET ~func(B) func(S1) S2, FCT ~func(S1) B, S1, S2, B, HKTS1, HKTS2 any](
|
|
||||||
mmap func(func(S1) S2) func(HKTS1) HKTS2,
|
|
||||||
s SET,
|
|
||||||
f FCT,
|
|
||||||
) func(HKTS1) HKTS2 {
|
|
||||||
return mmap(F.Flow3(
|
|
||||||
T.Replicate2[S1],
|
|
||||||
T.Map2(F.Flow2(
|
|
||||||
I.Ap[S2, S1],
|
|
||||||
F.Bind1st(F.Flow2[SET, func(func(S1) S2) S2], s)), f),
|
|
||||||
T.Tupled2(I.MonadAp[S2, B]),
|
|
||||||
))
|
|
||||||
}
|
|
@@ -43,19 +43,68 @@ func MonadChain[A, B, HKTA, HKTB any](
|
|||||||
// HKTA=HKT[A]
|
// HKTA=HKT[A]
|
||||||
// HKTB=HKT[B]
|
// HKTB=HKT[B]
|
||||||
func ChainFirst[A, B, HKTA, HKTB any](
|
func ChainFirst[A, B, HKTA, HKTB any](
|
||||||
mchain func(HKTA, func(A) HKTA) HKTA,
|
mchain func(func(A) HKTA) func(HKTA) HKTA,
|
||||||
mmap func(HKTB, func(B) A) HKTA,
|
mmap func(func(B) A) func(HKTB) HKTA,
|
||||||
f func(A) HKTB) func(HKTA) HKTA {
|
f func(A) HKTB) func(HKTA) HKTA {
|
||||||
return F.Bind2nd(mchain, func(a A) HKTA {
|
return mchain(func(a A) HKTA {
|
||||||
return mmap(f(a), F.Constant1[B](a))
|
return mmap(F.Constant1[B](a))(f(a))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func Chain[A, B, HKTA, HKTB any](
|
func Chain[A, B, HKTA, HKTB any](
|
||||||
mchain func(HKTA, func(A) HKTB) HKTB,
|
mchain func(func(A) HKTB) func(HKTA) HKTB,
|
||||||
f func(A) HKTB,
|
f func(A) HKTB,
|
||||||
) func(HKTA) HKTB {
|
) func(HKTA) HKTB {
|
||||||
return func(first HKTA) HKTB {
|
return mchain(f)
|
||||||
return MonadChain[A, B](mchain, first, f)
|
}
|
||||||
}
|
|
||||||
|
func MonadBind[S1, S2, B, HKTS1, HKTS2, HKTB any](
|
||||||
|
mchain func(HKTS1, func(S1) HKTS2) HKTS2,
|
||||||
|
mmap func(HKTB, func(B) S2) HKTS2,
|
||||||
|
first HKTS1,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
f func(S1) HKTB,
|
||||||
|
) HKTS2 {
|
||||||
|
return mchain(first, func(s1 S1) HKTS2 {
|
||||||
|
return mmap(f(s1), func(b B) S2 {
|
||||||
|
return key(b)(s1)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Bind[S1, S2, B, HKTS1, HKTS2, HKTB any](
|
||||||
|
mchain func(func(S1) HKTS2) func(HKTS1) HKTS2,
|
||||||
|
mmap func(func(B) S2) func(HKTB) HKTS2,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
f func(S1) HKTB,
|
||||||
|
) func(HKTS1) HKTS2 {
|
||||||
|
mapb := F.Flow2(
|
||||||
|
F.Flip(key),
|
||||||
|
mmap,
|
||||||
|
)
|
||||||
|
return mchain(func(s1 S1) HKTS2 {
|
||||||
|
return F.Pipe2(
|
||||||
|
s1,
|
||||||
|
f,
|
||||||
|
F.Pipe1(
|
||||||
|
s1,
|
||||||
|
mapb,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func BindTo[S1, B, HKTS1, HKTB any](
|
||||||
|
mmap func(func(B) S1) func(HKTB) HKTS1,
|
||||||
|
key func(B) S1,
|
||||||
|
) func(fa HKTB) HKTS1 {
|
||||||
|
return mmap(key)
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadBindTo[S1, B, HKTS1, HKTB any](
|
||||||
|
mmap func(HKTB, func(B) S1) HKTS1,
|
||||||
|
first HKTB,
|
||||||
|
key func(B) S1,
|
||||||
|
) HKTS1 {
|
||||||
|
return mmap(first, key)
|
||||||
}
|
}
|
||||||
|
@@ -30,7 +30,6 @@ import (
|
|||||||
func AssertAssociativity[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
func AssertAssociativity[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
||||||
eq E.Eq[HKTC],
|
eq E.Eq[HKTC],
|
||||||
|
|
||||||
fofa func(A) HKTA,
|
|
||||||
fofb func(B) HKTB,
|
fofb func(B) HKTB,
|
||||||
fofc func(C) HKTC,
|
fofc func(C) HKTC,
|
||||||
|
|
||||||
@@ -61,7 +60,6 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
|
|||||||
eqa E.Eq[HKTA],
|
eqa E.Eq[HKTA],
|
||||||
eqc E.Eq[HKTC],
|
eqc E.Eq[HKTC],
|
||||||
|
|
||||||
fofa func(A) HKTA,
|
|
||||||
fofb func(B) HKTB,
|
fofb func(B) HKTB,
|
||||||
fofc func(C) HKTC,
|
fofc func(C) HKTC,
|
||||||
|
|
||||||
@@ -91,7 +89,7 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAB, HKTBC, HKTAC, HKTABAC, A, B, C any](t *
|
|||||||
// apply laws
|
// apply laws
|
||||||
apply := L.AssertLaws(t, eqa, eqc, fofab, fofbc, faa, fab, fac, fbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
|
apply := L.AssertLaws(t, eqa, eqc, fofab, fofbc, faa, fab, fac, fbc, fmap, fapab, fapbc, fapac, fapabac, ab, bc)
|
||||||
// chain laws
|
// chain laws
|
||||||
associativity := AssertAssociativity(t, eqc, fofa, fofb, fofc, chainab, chainac, chainbc, ab, bc)
|
associativity := AssertAssociativity(t, eqc, fofb, fofc, chainab, chainac, chainbc, ab, bc)
|
||||||
|
|
||||||
return func(fa HKTA) bool {
|
return func(fa HKTA) bool {
|
||||||
return apply(fa) && associativity(fa)
|
return apply(fa) && associativity(fa)
|
||||||
|
25
internal/chain/types.go
Normal file
25
internal/chain/types.go
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// Copyright (c) 2024 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 chain
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/apply"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Chainable[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||||
|
apply.Apply[A, B, HKTA, HKTB, HKTFAB]
|
||||||
|
Chain(func(A) HKTB) func(HKTA) HKTB
|
||||||
|
}
|
@@ -51,6 +51,14 @@ func MonadMap[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A])
|
|||||||
return FC.MonadMap(fmap, ET.MonadMap[E, A, B], fa, f)
|
return FC.MonadMap(fmap, ET.MonadMap[E, A, B], fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[E, A, B, HKTFA, HKTFB any](
|
||||||
|
fmap func(func(ET.Either[E, A]) ET.Either[E, B]) func(HKTFA) HKTFB,
|
||||||
|
f func(A) B) func(HKTFA) HKTFB {
|
||||||
|
// HKTGA = Either[E, A]
|
||||||
|
// HKTGB = Either[E, B]
|
||||||
|
return FC.Map(fmap, ET.Map[E, A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
// HKTFA = HKT<F, Either<E, A>>
|
// HKTFA = HKT<F, Either<E, A>>
|
||||||
// HKTFB = HKT<F, Either<E, B>>
|
// HKTFB = HKT<F, Either<E, B>>
|
||||||
func MonadBiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E1, A]) ET.Either[E2, B]) HKTFB, fa HKTFA, f func(E1) E2, g func(A) B) HKTFB {
|
func MonadBiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E1, A]) ET.Either[E2, B]) HKTFB, fa HKTFA, f func(E1) E2, g func(A) B) HKTFB {
|
||||||
@@ -61,10 +69,12 @@ func MonadBiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[
|
|||||||
|
|
||||||
// HKTFA = HKT<F, Either<E, A>>
|
// HKTFA = HKT<F, Either<E, A>>
|
||||||
// HKTFB = HKT<F, Either<E, B>>
|
// HKTFB = HKT<F, Either<E, B>>
|
||||||
func BiMap[E1, E2, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E1, A]) ET.Either[E2, B]) HKTFB, f func(E1) E2, g func(A) B) func(HKTFA) HKTFB {
|
func BiMap[E1, E2, A, B, HKTFA, HKTFB any](
|
||||||
|
fmap func(func(ET.Either[E1, A]) ET.Either[E2, B]) func(HKTFA) HKTFB,
|
||||||
|
f func(E1) E2, g func(A) B) func(HKTFA) HKTFB {
|
||||||
// HKTGA = Either[E, A]
|
// HKTGA = Either[E, A]
|
||||||
// HKTGB = Either[E, B]
|
// HKTGB = Either[E, B]
|
||||||
return F.Bind2nd(fmap, ET.BiMap(f, g))
|
return fmap(ET.BiMap(f, g))
|
||||||
}
|
}
|
||||||
|
|
||||||
// HKTFA = HKT<F, Either<E, A>>
|
// HKTFA = HKT<F, Either<E, A>>
|
||||||
@@ -78,22 +88,29 @@ func MonadChain[E, A, B, HKTFA, HKTFB any](
|
|||||||
return fchain(ma, ET.Fold(F.Flow2(ET.Left[B, E], fof), f))
|
return fchain(ma, ET.Fold(F.Flow2(ET.Left[B, E], fof), f))
|
||||||
}
|
}
|
||||||
|
|
||||||
// func(fa func(R) T.Task[ET.Either[E, func(A) B]], f func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) GEFAB
|
func Chain[E, A, B, HKTFA, HKTFB any](
|
||||||
|
fchain func(func(ET.Either[E, A]) HKTFB) func(HKTFA) HKTFB,
|
||||||
|
fof func(ET.Either[E, B]) HKTFB,
|
||||||
|
f func(A) HKTFB) func(HKTFA) HKTFB {
|
||||||
|
// dispatch to the even more generic implementation
|
||||||
|
return fchain(ET.Fold(F.Flow2(ET.Left[B, E], fof), f))
|
||||||
|
}
|
||||||
|
|
||||||
// HKTFA = HKT[Either[E, A]]
|
|
||||||
// HKTFB = HKT[Either[E, B]]
|
|
||||||
// HKTFAB = HKT[Either[E, func(A)B]]
|
|
||||||
func MonadAp[E, A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
func MonadAp[E, A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||||
fap func(HKTFGAB, HKTFA) HKTFB,
|
fap func(HKTFGAB, HKTFA) HKTFB,
|
||||||
fmap func(HKTFAB, func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) HKTFGAB,
|
fmap func(HKTFAB, func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) HKTFGAB,
|
||||||
fab HKTFAB,
|
fab HKTFAB,
|
||||||
fa HKTFA) HKTFB {
|
fa HKTFA) HKTFB {
|
||||||
// HKTGA = ET.Either[E, A]
|
|
||||||
// HKTGB = ET.Either[E, B]
|
|
||||||
// HKTGAB = ET.Either[E, func(a A) B]
|
|
||||||
return apply.MonadAp(fap, fmap, ET.MonadAp[B, E, A], fab, fa)
|
return apply.MonadAp(fap, fmap, ET.MonadAp[B, E, A], fab, fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Ap[E, A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||||
|
fap func(HKTFA) func(HKTFGAB) HKTFB,
|
||||||
|
fmap func(func(ET.Either[E, func(A) B]) func(ET.Either[E, A]) ET.Either[E, B]) func(HKTFAB) HKTFGAB,
|
||||||
|
fa HKTFA) func(HKTFAB) HKTFB {
|
||||||
|
return apply.Ap(fap, fmap, ET.Ap[B, E, A], fa)
|
||||||
|
}
|
||||||
|
|
||||||
func Right[E, A, HKTA any](fof func(ET.Either[E, A]) HKTA, a A) HKTA {
|
func Right[E, A, HKTA any](fof func(ET.Either[E, A]) HKTA, a A) HKTA {
|
||||||
return F.Pipe2(a, ET.Right[E, A], fof)
|
return F.Pipe2(a, ET.Right[E, A], fof)
|
||||||
}
|
}
|
||||||
@@ -142,3 +159,7 @@ func OrLeft[E1, E2, A, HKTE1A, HKTE2, HKTE2A any](
|
|||||||
func MonadMapLeft[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[B, A]) HKTFB, fa HKTFA, f func(E) B) HKTFB {
|
func MonadMapLeft[E, A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(ET.Either[E, A]) ET.Either[B, A]) HKTFB, fa HKTFA, f func(E) B) HKTFB {
|
||||||
return FC.MonadMap(fmap, ET.MonadMapLeft[E, A, B], fa, f)
|
return FC.MonadMap(fmap, ET.MonadMapLeft[E, A, B], fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MapLeft[E, A, B, HKTFA, HKTFB any](fmap func(func(ET.Either[E, A]) ET.Either[B, A]) func(HKTFA) HKTFB, f func(E) B) func(HKTFA) HKTFB {
|
||||||
|
return FC.Map(fmap, ET.MapLeft[A, E, B], f)
|
||||||
|
}
|
||||||
|
26
internal/foldable/types.go
Normal file
26
internal/foldable/types.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024 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 foldable
|
||||||
|
|
||||||
|
import (
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Foldable[A, B, HKTA any] interface {
|
||||||
|
Reduce(func(B, A) B, B) func(HKTA) B
|
||||||
|
ReduceRight(func(B, A) B, B) func(HKTA) B
|
||||||
|
FoldMap(m M.Monoid[B]) func(func(A) B) func(HKTA) B
|
||||||
|
}
|
@@ -60,6 +60,13 @@ func MonadChainEitherK[A, E, B, HKTEA, HKTEB any](
|
|||||||
return mchain(ma, F.Flow2(f, fromEither))
|
return mchain(ma, F.Flow2(f, fromEither))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChainEitherK[A, E, B, HKTEA, HKTEB any](
|
||||||
|
mchain func(func(A) HKTEB) func(HKTEA) HKTEB,
|
||||||
|
fromEither func(ET.Either[E, B]) HKTEB,
|
||||||
|
f func(A) ET.Either[E, B]) func(HKTEA) HKTEB {
|
||||||
|
return mchain(F.Flow2(f, fromEither))
|
||||||
|
}
|
||||||
|
|
||||||
func ChainOptionK[A, E, B, HKTEA, HKTEB any](
|
func ChainOptionK[A, E, B, HKTEA, HKTEB any](
|
||||||
mchain func(HKTEA, func(A) HKTEB) HKTEB,
|
mchain func(HKTEA, func(A) HKTEB) HKTEB,
|
||||||
fromEither func(ET.Either[E, B]) HKTEB,
|
fromEither func(ET.Either[E, B]) HKTEB,
|
||||||
@@ -78,8 +85,8 @@ func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirstEitherK[A, E, B, HKTEA, HKTEB any](
|
func ChainFirstEitherK[A, E, B, HKTEA, HKTEB any](
|
||||||
mchain func(HKTEA, func(A) HKTEA) HKTEA,
|
mchain func(func(A) HKTEA) func(HKTEA) HKTEA,
|
||||||
mmap func(HKTEB, func(B) A) HKTEA,
|
mmap func(func(B) A) func(HKTEB) HKTEA,
|
||||||
fromEither func(ET.Either[E, B]) HKTEB,
|
fromEither func(ET.Either[E, B]) HKTEB,
|
||||||
f func(A) ET.Either[E, B]) func(HKTEA) HKTEA {
|
f func(A) ET.Either[E, B]) func(HKTEA) HKTEA {
|
||||||
return C.ChainFirst(mchain, mmap, F.Flow2(f, fromEither))
|
return C.ChainFirst(mchain, mmap, F.Flow2(f, fromEither))
|
||||||
|
24
internal/fromeither/types.go
Normal file
24
internal/fromeither/types.go
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
// Copyright (c) 2024 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 fromeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
)
|
||||||
|
|
||||||
|
type FromEither[E, A, HKTA any] interface {
|
||||||
|
FromEither(ET.Either[E, A]) HKTA
|
||||||
|
}
|
@@ -30,8 +30,8 @@ func MonadChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B](
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B](
|
func ChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B](
|
||||||
mchain func(HKTA, func(A) HKTA) HKTA,
|
mchain func(func(A) HKTA) func(HKTA) HKTA,
|
||||||
mmap func(HKTB, func(B) A) HKTA,
|
mmap func(func(B) A) func(HKTB) HKTA,
|
||||||
fromio func(GIOB) HKTB,
|
fromio func(GIOB) HKTB,
|
||||||
f func(A) GIOB) func(HKTA) HKTA {
|
f func(A) GIOB) func(HKTA) HKTA {
|
||||||
// chain
|
// chain
|
||||||
@@ -47,7 +47,7 @@ func MonadChainIOK[GR ~func() B, A, B, HKTA, HKTB any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainIOK[GR ~func() B, A, B, HKTA, HKTB any](
|
func ChainIOK[GR ~func() B, A, B, HKTA, HKTB any](
|
||||||
mchain func(HKTA, func(A) HKTB) HKTB,
|
mchain func(func(A) HKTB) func(HKTA) HKTB,
|
||||||
fromio func(GR) HKTB,
|
fromio func(GR) HKTB,
|
||||||
f func(A) GR) func(HKTA) HKTB {
|
f func(A) GR) func(HKTA) HKTB {
|
||||||
// chain
|
// chain
|
||||||
|
20
internal/fromio/types.go
Normal file
20
internal/fromio/types.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// Copyright (c) 2024 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 fromio
|
||||||
|
|
||||||
|
type FromIO[A, GA ~func() A, HKTA any] interface {
|
||||||
|
FromIO(GA) HKTA
|
||||||
|
}
|
@@ -31,8 +31,8 @@ func MonadChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
func ChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||||
mchain func(HKTA, func(A) HKTA) HKTA,
|
mchain func(func(A) HKTA) func(HKTA) HKTA,
|
||||||
mmap func(HKTB, func(B) A) HKTA,
|
mmap func(func(B) A) func(HKTB) HKTA,
|
||||||
fromio func(GIOB) HKTB,
|
fromio func(GIOB) HKTB,
|
||||||
f func(A) GIOB) func(HKTA) HKTA {
|
f func(A) GIOB) func(HKTA) HKTA {
|
||||||
// chain
|
// chain
|
||||||
@@ -48,7 +48,7 @@ func MonadChainIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
func ChainIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any](
|
||||||
mchain func(HKTA, func(A) HKTB) HKTB,
|
mchain func(func(A) HKTB) func(HKTA) HKTB,
|
||||||
fromio func(GIOB) HKTB,
|
fromio func(GIOB) HKTB,
|
||||||
f func(A) GIOB) func(HKTA) HKTB {
|
f func(A) GIOB) func(HKTA) HKTB {
|
||||||
// chain
|
// chain
|
||||||
|
@@ -15,23 +15,24 @@
|
|||||||
|
|
||||||
package functor
|
package functor
|
||||||
|
|
||||||
|
func flap[FAB ~func(A) B, A, B any](a A) func(FAB) B {
|
||||||
|
return func(f FAB) B {
|
||||||
|
return f(a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadFlap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
func MonadFlap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||||
fmap func(HKTFAB, func(FAB) B) HKTB,
|
fmap func(HKTFAB, func(FAB) B) HKTB,
|
||||||
|
|
||||||
fab HKTFAB,
|
fab HKTFAB,
|
||||||
a A,
|
a A,
|
||||||
) HKTB {
|
) HKTB {
|
||||||
return fmap(fab, func(f FAB) B {
|
return fmap(fab, flap[FAB, A, B](a))
|
||||||
return f(a)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
func Flap[FAB ~func(A) B, A, B, HKTFAB, HKTB any](
|
||||||
fmap func(HKTFAB, func(FAB) B) HKTB,
|
fmap func(func(FAB) B) func(HKTFAB) HKTB,
|
||||||
|
|
||||||
a A,
|
a A,
|
||||||
) func(HKTFAB) HKTB {
|
) func(HKTFAB) HKTB {
|
||||||
return func(fab HKTFAB) HKTB {
|
return fmap(flap[FAB, A, B](a))
|
||||||
return MonadFlap(fmap, fab, a)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,46 @@ import (
|
|||||||
|
|
||||||
// HKTFGA = HKT[F, HKT[G, A]]
|
// HKTFGA = HKT[F, HKT[G, A]]
|
||||||
// HKTFGB = HKT[F, HKT[G, B]]
|
// HKTFGB = HKT[F, HKT[G, B]]
|
||||||
func MonadMap[A, B, HKTGA, HKTGB, HKTFGA, HKTFGB any](fmap func(HKTFGA, func(HKTGA) HKTGB) HKTFGB, gmap func(HKTGA, func(A) B) HKTGB, fa HKTFGA, f func(A) B) HKTFGB {
|
func MonadMap[A, B, HKTGA, HKTGB, HKTFGA, HKTFGB any](
|
||||||
|
fmap func(HKTFGA, func(HKTGA) HKTGB) HKTFGB,
|
||||||
|
gmap func(HKTGA, func(A) B) HKTGB,
|
||||||
|
fa HKTFGA,
|
||||||
|
f func(A) B) HKTFGB {
|
||||||
return fmap(fa, F.Bind2nd(gmap, f))
|
return fmap(fa, F.Bind2nd(gmap, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[A, B, HKTGA, HKTGB, HKTFGA, HKTFGB any](
|
||||||
|
fmap func(func(HKTGA) HKTGB) func(HKTFGA) HKTFGB,
|
||||||
|
gmap func(func(A) B) func(HKTGA) HKTGB,
|
||||||
|
f func(A) B) func(HKTFGA) HKTFGB {
|
||||||
|
return fmap(gmap(f))
|
||||||
|
}
|
||||||
|
|
||||||
|
func MonadLet[S1, S2, B, HKTS1, HKTS2 any](
|
||||||
|
mmap func(HKTS1, func(S1) S2) HKTS2,
|
||||||
|
first HKTS1,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
f func(S1) B,
|
||||||
|
) HKTS2 {
|
||||||
|
return mmap(first, func(s1 S1) S2 {
|
||||||
|
return key(f(s1))(s1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func Let[S1, S2, B, HKTS1, HKTS2 any](
|
||||||
|
mmap func(func(S1) S2) func(HKTS1) HKTS2,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
f func(S1) B,
|
||||||
|
) func(HKTS1) HKTS2 {
|
||||||
|
return mmap(func(s1 S1) S2 {
|
||||||
|
return key(f(s1))(s1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func LetTo[S1, S2, B, HKTS1, HKTS2 any](
|
||||||
|
mmap func(func(S1) S2) func(HKTS1) HKTS2,
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(HKTS1) HKTS2 {
|
||||||
|
return mmap(key(b))
|
||||||
|
}
|
||||||
|
@@ -27,6 +27,7 @@ import (
|
|||||||
//
|
//
|
||||||
// F.map(fa, a => a) <-> fa
|
// F.map(fa, a => a) <-> fa
|
||||||
func AssertIdentity[HKTA, A any](t *testing.T, eq E.Eq[HKTA], fmap func(HKTA, func(A) A) HKTA) func(fa HKTA) bool {
|
func AssertIdentity[HKTA, A any](t *testing.T, eq E.Eq[HKTA], fmap func(HKTA, func(A) A) HKTA) func(fa HKTA) bool {
|
||||||
|
t.Helper()
|
||||||
return func(fa HKTA) bool {
|
return func(fa HKTA) bool {
|
||||||
return assert.True(t, eq.Equals(fa, fmap(fa, F.Identity[A])), "Functor identity law")
|
return assert.True(t, eq.Equals(fa, fmap(fa, F.Identity[A])), "Functor identity law")
|
||||||
}
|
}
|
||||||
@@ -46,6 +47,7 @@ func AssertComposition[HKTA, HKTB, HKTC, A, B, C any](
|
|||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
bc func(B) C,
|
bc func(B) C,
|
||||||
) func(fa HKTA) bool {
|
) func(fa HKTA) bool {
|
||||||
|
t.Helper()
|
||||||
return func(fa HKTA) bool {
|
return func(fa HKTA) bool {
|
||||||
return assert.True(t, eq.Equals(fac(fa, F.Flow2(ab, bc)), fbc(fab(fa, ab), bc)), "Functor composition law")
|
return assert.True(t, eq.Equals(fac(fa, F.Flow2(ab, bc)), fbc(fab(fa, ab), bc)), "Functor composition law")
|
||||||
}
|
}
|
||||||
@@ -63,6 +65,7 @@ func AssertLaws[HKTA, HKTB, HKTC, A, B, C any](t *testing.T,
|
|||||||
ab func(A) B,
|
ab func(A) B,
|
||||||
bc func(B) C,
|
bc func(B) C,
|
||||||
) func(fa HKTA) bool {
|
) func(fa HKTA) bool {
|
||||||
|
t.Helper()
|
||||||
identity := AssertIdentity(t, eqa, faa)
|
identity := AssertIdentity(t, eqa, faa)
|
||||||
composition := AssertComposition(t, eqc, fab, fac, fbc, ab, bc)
|
composition := AssertComposition(t, eqc, fab, fac, fbc, ab, bc)
|
||||||
|
|
||||||
|
20
internal/functor/types.go
Normal file
20
internal/functor/types.go
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// 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
|
||||||
|
|
||||||
|
type Functor[A, B, HKTA, HKTB any] interface {
|
||||||
|
Map(func(A) B) func(HKTA) HKTB
|
||||||
|
}
|
26
internal/monad/monad.go
Normal file
26
internal/monad/monad.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024 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 monad
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/applicative"
|
||||||
|
"github.com/IBM/fp-go/internal/chain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Monad[A, B, HKTA, HKTB, HKTFAB any] interface {
|
||||||
|
applicative.Applicative[A, B, HKTA, HKTB, HKTFAB]
|
||||||
|
chain.Chainable[A, B, HKTA, HKTB, HKTFAB]
|
||||||
|
}
|
@@ -110,7 +110,7 @@ func AssertLaws[HKTA, HKTB, HKTC, HKTAA, HKTAB, HKTBC, HKTAC, HKTABB, HKTABAC, A
|
|||||||
// applicative laws
|
// applicative laws
|
||||||
applicative := LA.AssertLaws(t, eqa, eqb, eqc, fofa, fofb, fofaa, fofab, fofbc, fofabb, faa, fab, fac, fbc, fmap, fapaa, fapab, fapbc, fapac, fapabb, fapabac, ab, bc)
|
applicative := LA.AssertLaws(t, eqa, eqb, eqc, fofa, fofb, fofaa, fofab, fofbc, fofabb, faa, fab, fac, fbc, fmap, fapaa, fapab, fapbc, fapac, fapabb, fapabac, ab, bc)
|
||||||
// chain laws
|
// chain laws
|
||||||
chain := LC.AssertLaws(t, eqa, eqc, fofa, fofb, fofc, fofab, fofbc, faa, fab, fac, fbc, fmap, chainab, chainac, chainbc, fapab, fapbc, fapac, fapabac, ab, bc)
|
chain := LC.AssertLaws(t, eqa, eqc, fofb, fofc, fofab, fofbc, faa, fab, fac, fbc, fmap, chainab, chainac, chainbc, fapab, fapbc, fapac, fapabac, ab, bc)
|
||||||
// monad laws
|
// monad laws
|
||||||
leftIdentity := AssertLeftIdentity(t, eqb, fofa, fofb, chainab, ab)
|
leftIdentity := AssertLeftIdentity(t, eqb, fofa, fofb, chainab, ab)
|
||||||
rightIdentity := AssertRightIdentity(t, eqa, fofa, chainaa)
|
rightIdentity := AssertRightIdentity(t, eqa, fofa, chainaa)
|
||||||
|
@@ -40,6 +40,12 @@ func MonadMap[A, B, HKTFA, HKTFB any](fmap func(HKTFA, func(O.Option[A]) O.Optio
|
|||||||
return FC.MonadMap(fmap, O.MonadMap[A, B], fa, f)
|
return FC.MonadMap(fmap, O.MonadMap[A, B], fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[A, B, HKTFA, HKTFB any](fmap func(func(O.Option[A]) O.Option[B]) func(HKTFA) HKTFB, f func(A) B) func(HKTFA) HKTFB {
|
||||||
|
// HKTGA = Either[E, A]
|
||||||
|
// HKTGB = Either[E, B]
|
||||||
|
return FC.Map(fmap, O.Map[A, B], f)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChain[A, B, HKTFA, HKTFB any](
|
func MonadChain[A, B, HKTFA, HKTFB any](
|
||||||
fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB,
|
fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB,
|
||||||
fof func(O.Option[B]) HKTFB,
|
fof func(O.Option[B]) HKTFB,
|
||||||
@@ -50,13 +56,11 @@ func MonadChain[A, B, HKTFA, HKTFB any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Chain[A, B, HKTFA, HKTFB any](
|
func Chain[A, B, HKTFA, HKTFB any](
|
||||||
fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB,
|
fchain func(func(O.Option[A]) HKTFB) func(HKTFA) HKTFB,
|
||||||
fof func(O.Option[B]) HKTFB,
|
fof func(O.Option[B]) HKTFB,
|
||||||
f func(A) HKTFB) func(ma HKTFA) HKTFB {
|
f func(A) HKTFB) func(ma HKTFA) HKTFB {
|
||||||
// dispatch to the even more generic implementation
|
// dispatch to the even more generic implementation
|
||||||
return func(ma HKTFA) HKTFB {
|
return fchain(O.Fold(F.Nullary2(O.None[B], fof), f))
|
||||||
return MonadChain(fchain, fof, ma, f)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||||
@@ -64,12 +68,16 @@ func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
|||||||
fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB,
|
fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB,
|
||||||
fab HKTFAB,
|
fab HKTFAB,
|
||||||
fa HKTFA) HKTFB {
|
fa HKTFA) HKTFB {
|
||||||
// HKTGA = O.Option[A]
|
|
||||||
// HKTGB = O.Option[B]
|
|
||||||
// HKTGAB = O.Option[func(a A) B]
|
|
||||||
return apply.MonadAp(fap, fmap, O.MonadAp[B, A], fab, fa)
|
return apply.MonadAp(fap, fmap, O.MonadAp[B, A], fab, fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Ap[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any](
|
||||||
|
fap func(HKTFA) func(HKTFGAB) HKTFB,
|
||||||
|
fmap func(func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) func(HKTFAB) HKTFGAB,
|
||||||
|
fa HKTFA) func(HKTFAB) HKTFB {
|
||||||
|
return apply.Ap(fap, fmap, O.Ap[B, A], fa)
|
||||||
|
}
|
||||||
|
|
||||||
func MatchE[A, HKTEA, HKTB any](mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB, onNone func() HKTB, onSome func(A) HKTB) func(HKTEA) HKTB {
|
func MatchE[A, HKTEA, HKTB any](mchain func(HKTEA, func(O.Option[A]) HKTB) HKTB, onNone func() HKTB, onSome func(A) HKTB) func(HKTEA) HKTB {
|
||||||
return F.Bind2nd(mchain, O.Fold(onNone, onSome))
|
return F.Bind2nd(mchain, O.Fold(onNone, onSome))
|
||||||
}
|
}
|
||||||
@@ -89,6 +97,14 @@ func MonadChainOptionK[A, B, HKTA, HKTB any](
|
|||||||
return MonadChain(fchain, fof, ma, FromOptionK(fof, f))
|
return MonadChain(fchain, fof, ma, FromOptionK(fof, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ChainOptionK[A, B, HKTA, HKTB any](
|
||||||
|
fchain func(func(O.Option[A]) HKTB) func(HKTA) HKTB,
|
||||||
|
fof func(O.Option[B]) HKTB,
|
||||||
|
f func(A) O.Option[B],
|
||||||
|
) func(HKTA) HKTB {
|
||||||
|
return Chain(fchain, fof, FromOptionK(fof, f))
|
||||||
|
}
|
||||||
|
|
||||||
func MonadAlt[LAZY ~func() HKTFA, A, HKTFA any](
|
func MonadAlt[LAZY ~func() HKTFA, A, HKTFA any](
|
||||||
fof func(O.Option[A]) HKTFA,
|
fof func(O.Option[A]) HKTFA,
|
||||||
fchain func(HKTFA, func(O.Option[A]) HKTFA) HKTFA,
|
fchain func(HKTFA, func(O.Option[A]) HKTFA) HKTFA,
|
||||||
@@ -101,11 +117,9 @@ func MonadAlt[LAZY ~func() HKTFA, A, HKTFA any](
|
|||||||
|
|
||||||
func Alt[LAZY ~func() HKTFA, A, HKTFA any](
|
func Alt[LAZY ~func() HKTFA, A, HKTFA any](
|
||||||
fof func(O.Option[A]) HKTFA,
|
fof func(O.Option[A]) HKTFA,
|
||||||
fchain func(HKTFA, func(O.Option[A]) HKTFA) HKTFA,
|
fchain func(func(O.Option[A]) HKTFA) func(HKTFA) HKTFA,
|
||||||
|
|
||||||
second LAZY) func(HKTFA) HKTFA {
|
second LAZY) func(HKTFA) HKTFA {
|
||||||
|
|
||||||
return func(fa HKTFA) HKTFA {
|
return fchain(O.Fold(second, F.Flow2(O.Of[A], fof)))
|
||||||
return MonadAlt(fof, fchain, fa, second)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
21
internal/pointed/types.go
Normal file
21
internal/pointed/types.go
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
// 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 pointed
|
||||||
|
|
||||||
|
type Pointed[A, HKTA any] interface {
|
||||||
|
// Of lifts a value into its higher kinded type
|
||||||
|
Of(A) HKTA
|
||||||
|
}
|
@@ -23,10 +23,25 @@ import (
|
|||||||
// here we implement the monadic operations using callbacks from
|
// here we implement the monadic operations using callbacks from
|
||||||
// higher kinded types, as good a golang allows use to do this
|
// higher kinded types, as good a golang allows use to do this
|
||||||
|
|
||||||
func MonadMap[GEA ~func(E) HKTA, GEB ~func(E) HKTB, E, A, B, HKTA, HKTB any](fmap func(HKTA, func(A) B) HKTB, fa GEA, f func(A) B) GEB {
|
func MonadMap[GEA ~func(E) HKTA, GEB ~func(E) HKTB, E, A, B, HKTA, HKTB any](
|
||||||
|
fmap func(HKTA, func(A) B) HKTB,
|
||||||
|
fa GEA,
|
||||||
|
f func(A) B,
|
||||||
|
) GEB {
|
||||||
return R.MonadMap[GEA, GEB](fa, F.Bind2nd(fmap, f))
|
return R.MonadMap[GEA, GEB](fa, F.Bind2nd(fmap, f))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Map[GEA ~func(E) HKTA, GEB ~func(E) HKTB, E, A, B, HKTA, HKTB any](
|
||||||
|
fmap func(func(A) B) func(HKTA) HKTB,
|
||||||
|
f func(A) B,
|
||||||
|
) func(GEA) GEB {
|
||||||
|
return F.Pipe2(
|
||||||
|
f,
|
||||||
|
fmap,
|
||||||
|
R.Map[GEA, GEB, E, HKTA, HKTB],
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadChain[GEA ~func(E) HKTA, GEB ~func(E) HKTB, A, E, HKTA, HKTB any](fchain func(HKTA, func(A) HKTB) HKTB, ma GEA, f func(A) GEB) GEB {
|
func MonadChain[GEA ~func(E) HKTA, GEB ~func(E) HKTB, A, E, HKTA, HKTB any](fchain func(HKTA, func(A) HKTB) HKTB, ma GEA, f func(A) GEB) GEB {
|
||||||
return R.MakeReader(func(r E) HKTB {
|
return R.MakeReader(func(r E) HKTB {
|
||||||
return fchain(ma(r), func(a A) HKTB {
|
return fchain(ma(r), func(a A) HKTB {
|
||||||
|
59
internal/utils/do.go
Normal file
59
internal/utils/do.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 utils
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
)
|
||||||
|
|
||||||
|
type (
|
||||||
|
Initial struct {
|
||||||
|
}
|
||||||
|
|
||||||
|
WithLastName struct {
|
||||||
|
Initial
|
||||||
|
LastName string
|
||||||
|
}
|
||||||
|
|
||||||
|
WithGivenName struct {
|
||||||
|
WithLastName
|
||||||
|
GivenName string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
Empty = Initial{}
|
||||||
|
|
||||||
|
SetLastName = F.Curry2(func(name string, s1 Initial) WithLastName {
|
||||||
|
return WithLastName{
|
||||||
|
Initial: s1,
|
||||||
|
LastName: name,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
SetGivenName = F.Curry2(func(name string, s1 WithLastName) WithGivenName {
|
||||||
|
return WithGivenName{
|
||||||
|
WithLastName: s1,
|
||||||
|
GivenName: name,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
|
func GetFullName(s WithGivenName) string {
|
||||||
|
return fmt.Sprintf("%s %s", s.GivenName, s.LastName)
|
||||||
|
}
|
66
io/bind.go
Normal file
66
io/bind.go
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
// 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"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) IO[S] {
|
||||||
|
return G.Do[IO[S], S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) IO[T],
|
||||||
|
) func(IO[S1]) IO[S2] {
|
||||||
|
return G.Bind[IO[S1], IO[S2], IO[T], S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(IO[S1]) IO[S2] {
|
||||||
|
return G.Let[IO[S1], IO[S2], S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(IO[S1]) IO[S2] {
|
||||||
|
return G.LetTo[IO[S1], IO[S2], S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(IO[T]) IO[S1] {
|
||||||
|
return G.BindTo[IO[S1], IO[T], S1, T](setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa IO[T],
|
||||||
|
) func(IO[S1]) IO[S2] {
|
||||||
|
return G.ApS[IO[S1], IO[S2], IO[T], S1, S2, T](setter, fa)
|
||||||
|
}
|
56
io/bind_test.go
Normal file
56
io/bind_test.go
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package io
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) IO[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) IO[string] {
|
||||||
|
return Of("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), "John Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do(utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of("John")),
|
||||||
|
Map(utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), "John Doe")
|
||||||
|
}
|
89
io/generic/bind.go
Normal file
89
io/generic/bind.go
Normal file
@@ -0,0 +1,89 @@
|
|||||||
|
// 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 (
|
||||||
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~func() S, S any](
|
||||||
|
empty S,
|
||||||
|
) GS {
|
||||||
|
return Of[GS](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~func() S1, GS2 ~func() S2, GT ~func() T, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GS1, GS2, S1, S2],
|
||||||
|
Map[GT, GS2, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~func() S1, GS2 ~func() S2, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func() S1, GS2 ~func() S2, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func() S1, GT ~func() T, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[GS1 ~func() S1, GS2 ~func() S2, GT ~func() T, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GS2, func() func(T) S2, GT, S2, T],
|
||||||
|
Map[GS1, func() func(T) S2, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@@ -22,6 +22,12 @@ import (
|
|||||||
C "github.com/IBM/fp-go/internal/chain"
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
FC "github.com/IBM/fp-go/internal/functor"
|
FC "github.com/IBM/fp-go/internal/functor"
|
||||||
L "github.com/IBM/fp-go/internal/lazy"
|
L "github.com/IBM/fp-go/internal/lazy"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
// undefined represents an undefined value
|
||||||
|
undefined = struct{}{}
|
||||||
)
|
)
|
||||||
|
|
||||||
// type IO[A any] = func() A
|
// type IO[A any] = func() A
|
||||||
@@ -42,7 +48,7 @@ func FromIO[GA ~func() A, A any](a GA) GA {
|
|||||||
func FromImpure[GA ~func() any, IMP ~func()](f IMP) GA {
|
func FromImpure[GA ~func() any, IMP ~func()](f IMP) GA {
|
||||||
return MakeIO[GA](func() any {
|
return MakeIO[GA](func() any {
|
||||||
f()
|
f()
|
||||||
return nil
|
return undefined
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,7 +58,7 @@ func MonadOf[GA ~func() A, A any](a A) GA {
|
|||||||
|
|
||||||
func MonadMap[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) B) GB {
|
func MonadMap[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) B) GB {
|
||||||
return MakeIO[GB](func() B {
|
return MakeIO[GB](func() B {
|
||||||
return F.Pipe1(fa(), f)
|
return f(fa())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,13 +71,13 @@ func MonadMapTo[GA ~func() A, GB ~func() B, A, B any](fa GA, b B) GB {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MapTo[GA ~func() A, GB ~func() B, A, B any](b B) func(GA) GB {
|
func MapTo[GA ~func() A, GB ~func() B, A, B any](b B) func(GA) GB {
|
||||||
return F.Bind2nd(MonadMapTo[GA, GB, A, B], b)
|
return Map[GA, GB](F.Constant1[A](b))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
|
// MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
|
||||||
func MonadChain[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB) GB {
|
func MonadChain[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB) GB {
|
||||||
return MakeIO[GB](func() B {
|
return MakeIO[GB](func() B {
|
||||||
return F.Pipe1(fa(), f)()
|
return f(fa())()
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +93,7 @@ func MonadChainTo[GA ~func() A, GB ~func() B, A, B any](fa GA, fb GB) GB {
|
|||||||
|
|
||||||
// ChainTo composes computations in sequence, ignoring the return value of the first computation
|
// ChainTo composes computations in sequence, ignoring the return value of the first computation
|
||||||
func ChainTo[GA ~func() A, GB ~func() B, A, B any](fb GB) func(GA) GB {
|
func ChainTo[GA ~func() A, GB ~func() B, A, B any](fb GB) func(GA) GB {
|
||||||
return F.Bind2nd(MonadChainTo[GA, GB, A, B], fb)
|
return Chain[GA, GB](F.Constant1[A](fb))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MonadChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
|
// MonadChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
|
||||||
@@ -99,7 +105,11 @@ func MonadChainFirst[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB)
|
|||||||
// ChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
|
// ChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and
|
||||||
// keeping only the result of the first.
|
// keeping only the result of the first.
|
||||||
func ChainFirst[GA ~func() A, GB ~func() B, A, B any](f func(A) GB) func(GA) GA {
|
func ChainFirst[GA ~func() A, GB ~func() B, A, B any](f func(A) GB) func(GA) GA {
|
||||||
return C.ChainFirst(MonadChain[GA, GA, A, A], MonadMap[GB, GA, B, A], f)
|
return C.ChainFirst(
|
||||||
|
Chain[GA, GA, A, A],
|
||||||
|
Map[GB, GA, B, A],
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ApSeq[GB ~func() B, GAB ~func() func(A) B, GA ~func() A, B, A any](ma GA) func(GAB) GB {
|
func ApSeq[GB ~func() B, GAB ~func() func(A) B, GA ~func() A, B, A any](ma GA) func(GAB) GB {
|
||||||
@@ -173,5 +183,25 @@ func MonadFlap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](fab GFA
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Flap[FAB ~func(A) B, GFAB ~func() FAB, GB ~func() B, A, B any](a A) func(GFAB) GB {
|
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)
|
return FC.Flap(Map[GFAB, GB, FAB, B], a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithTime returns an operation that measures the start and end timestamp of the operation
|
||||||
|
func WithTime[GTA ~func() T.Tuple3[A, time.Time, time.Time], GA ~func() A, A any](a GA) GTA {
|
||||||
|
return MakeIO[GTA](func() T.Tuple3[A, time.Time, time.Time] {
|
||||||
|
t0 := time.Now()
|
||||||
|
res := a()
|
||||||
|
t1 := time.Now()
|
||||||
|
return T.MakeTuple3(res, t0, t1)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDuration returns an operation that measures the duration of the operation
|
||||||
|
func WithDuration[GTA ~func() T.Tuple2[A, time.Duration], GA ~func() A, A any](a GA) GTA {
|
||||||
|
return MakeIO[GTA](func() T.Tuple2[A, time.Duration] {
|
||||||
|
t0 := time.Now()
|
||||||
|
res := a()
|
||||||
|
t1 := time.Now()
|
||||||
|
return T.MakeTuple2(res, t1.Sub(t0))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
43
io/generic/monad.go
Normal file
43
io/generic/monad.go
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
// Copyright (c) 2024 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
)
|
||||||
|
|
||||||
|
type ioMonad[A, B any, GA ~func() A, GB ~func() B, GAB ~func() func(A) B] struct{}
|
||||||
|
|
||||||
|
func (o *ioMonad[A, B, GA, GB, GAB]) Of(a A) GA {
|
||||||
|
return Of[GA, A](a)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ioMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
|
||||||
|
return Map[GA, GB, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ioMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
|
||||||
|
return Chain[GA, GB, A, B](f)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (o *ioMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
|
||||||
|
return Ap[GB, GAB, GA, B, A](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Monad implements the monadic operations for [Option]
|
||||||
|
func Monad[A, B any, GA ~func() A, GB ~func() B, GAB ~func() func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
|
||||||
|
return &ioMonad[A, B, GA, GB, GAB]{}
|
||||||
|
}
|
13
io/io.go
13
io/io.go
@@ -19,6 +19,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
G "github.com/IBM/fp-go/io/generic"
|
G "github.com/IBM/fp-go/io/generic"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
)
|
)
|
||||||
|
|
||||||
// IO represents a synchronous computation that cannot fail
|
// IO represents a synchronous computation that cannot fail
|
||||||
@@ -143,7 +144,7 @@ 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)
|
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] {
|
func Flap[B, A 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)
|
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,3 +157,13 @@ func Delay[A any](delay time.Duration) func(IO[A]) IO[A] {
|
|||||||
func After[A any](timestamp time.Time) func(IO[A]) IO[A] {
|
func After[A any](timestamp time.Time) func(IO[A]) IO[A] {
|
||||||
return G.After[IO[A]](timestamp)
|
return G.After[IO[A]](timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// WithTime returns an operation that measures the start and end [time.Time] of the operation
|
||||||
|
func WithTime[A any](a IO[A]) IO[T.Tuple3[A, time.Time, time.Time]] {
|
||||||
|
return G.WithTime[IO[T.Tuple3[A, time.Time, time.Time]], IO[A]](a)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WithDuration returns an operation that measures the [time.Duration]
|
||||||
|
func WithDuration[A any](a IO[A]) IO[T.Tuple2[A, time.Duration]] {
|
||||||
|
return G.WithDuration[IO[T.Tuple2[A, time.Duration]], IO[A]](a)
|
||||||
|
}
|
||||||
|
@@ -27,7 +27,7 @@ func TestLogger(t *testing.T) {
|
|||||||
|
|
||||||
lio := l("out")
|
lio := l("out")
|
||||||
|
|
||||||
assert.Equal(t, nil, lio(10)())
|
assert.NotPanics(t, func() { lio(10)() })
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestLogf(t *testing.T) {
|
func TestLogf(t *testing.T) {
|
||||||
@@ -36,5 +36,5 @@ func TestLogf(t *testing.T) {
|
|||||||
|
|
||||||
lio := l("Value is %d")
|
lio := l("Value is %d")
|
||||||
|
|
||||||
assert.Equal(t, nil, lio(10)())
|
assert.NotPanics(t, func() { lio(10)() })
|
||||||
}
|
}
|
||||||
|
26
io/monad.go
Normal file
26
io/monad.go
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright (c) 2024 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 (
|
||||||
|
"github.com/IBM/fp-go/internal/monad"
|
||||||
|
G "github.com/IBM/fp-go/io/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Monad returns the monadic operations for [IO]
|
||||||
|
func Monad[A, B any]() monad.Monad[A, B, IO[A], IO[B], IO[func(A) B]] {
|
||||||
|
return G.Monad[A, B, IO[A], IO[B], IO[func(A) B]]()
|
||||||
|
}
|
@@ -19,26 +19,48 @@ import (
|
|||||||
G "github.com/IBM/fp-go/ioeither/generic"
|
G "github.com/IBM/fp-go/ioeither/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bind applies a function to an input state and merges the result into that state
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
func Bind[E, A, S1, S2 any](s func(A) func(S1) S2, f func(S1) IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
|
func Do[E, S any](
|
||||||
return G.Bind[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], func(S1) IOEither[E, A]](s, f)
|
empty S,
|
||||||
|
) IOEither[E, S] {
|
||||||
|
return G.Do[IOEither[E, S], E, S](empty)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindTo initializes some state based on a value
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
func BindTo[
|
func Bind[E, S1, S2, T any](
|
||||||
E, A, S2 any](s func(A) S2) func(IOEither[E, A]) IOEither[E, S2] {
|
setter func(T) func(S1) S2,
|
||||||
return G.BindTo[IOEither[E, S2], IOEither[E, A]](s)
|
f func(S1) IOEither[E, T],
|
||||||
}
|
|
||||||
|
|
||||||
func ApS[
|
|
||||||
E, A, S1, S2 any,
|
|
||||||
](s func(A) func(S1) S2, fa IOEither[E, A]) func(IOEither[E, S1]) IOEither[E, S2] {
|
|
||||||
return G.ApS[IOEither[E, S1], IOEither[E, S2], IOEither[E, A], IOEither[E, func(S1) S2]](s, fa)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Let[E, A, S1, S2 any](
|
|
||||||
s func(A) func(S1) S2,
|
|
||||||
f func(S1) A,
|
|
||||||
) func(IOEither[E, S1]) IOEither[E, S2] {
|
) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||||
return G.Let[IOEither[E, S1], IOEither[E, S2]](s, f)
|
return G.Bind[IOEither[E, S1], IOEither[E, S2], IOEither[E, T], E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||||
|
return G.Let[IOEither[E, S1], IOEither[E, S2], E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||||
|
return G.LetTo[IOEither[E, S1], IOEither[E, S2], E, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(IOEither[E, T]) IOEither[E, S1] {
|
||||||
|
return G.BindTo[IOEither[E, S1], IOEither[E, T], E, S1, T](setter)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa IOEither[E, T],
|
||||||
|
) func(IOEither[E, S1]) IOEither[E, S2] {
|
||||||
|
return G.ApS[IOEither[E, S1], IOEither[E, S2], IOEither[E, T], E, S1, S2, T](setter, fa)
|
||||||
}
|
}
|
||||||
|
57
ioeither/bind_test.go
Normal file
57
ioeither/bind_test.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 ioeither
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
E "github.com/IBM/fp-go/either"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) IOEither[error, string] {
|
||||||
|
return Of[error]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) IOEither[error, string] {
|
||||||
|
return Of[error]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[error](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), E.Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[error](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[error]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[error]("John")),
|
||||||
|
Map[error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), E.Of[error]("John Doe"))
|
||||||
|
}
|
@@ -26,7 +26,7 @@ func Eq[E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[IOEither[E, A]] {
|
|||||||
return G.Eq[IOEither[E, A]](eq)
|
return G.Eq[IOEither[E, A]](eq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[E, A comparable]() EQ.Eq[IOEither[E, A]] {
|
func FromStrictEquals[E, A comparable]() EQ.Eq[IOEither[E, A]] {
|
||||||
return G.FromStrictEquals[IOEither[E, A]]()
|
return G.FromStrictEquals[IOEither[E, A]]()
|
||||||
}
|
}
|
||||||
|
@@ -48,10 +48,10 @@ func ExampleIOEither_creation() {
|
|||||||
fmt.Println(rightFromPred())
|
fmt.Println(rightFromPred())
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Left[*errors.errorString, string](some error)
|
// Left[*errors.errorString](some error)
|
||||||
// Right[<nil>, string](value)
|
// Right[string](value)
|
||||||
// Right[<nil>, int](42)
|
// Right[int](42)
|
||||||
// Left[*errors.errorString, int](3 is an odd number)
|
// Left[*errors.errorString](3 is an odd number)
|
||||||
// Right[<nil>, int](4)
|
// Right[int](4)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -53,5 +53,5 @@ func ExampleIOEither_do() {
|
|||||||
fmt.Println(b())
|
fmt.Println(b())
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Right[<nil>, int](8)
|
// Right[int](8)
|
||||||
}
|
}
|
||||||
|
@@ -38,7 +38,7 @@ func ExampleIOEither_extraction() {
|
|||||||
fmt.Println(valueFromIO)
|
fmt.Println(valueFromIO)
|
||||||
|
|
||||||
// Output:
|
// Output:
|
||||||
// Right[<nil>, int](42)
|
// Right[int](42)
|
||||||
// 42
|
// 42
|
||||||
// 42
|
// 42
|
||||||
|
|
||||||
|
36
ioeither/file/dir.go
Normal file
36
ioeither/file/dir.go
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
// 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"
|
||||||
|
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MkdirAll create a sequence of directories, see [os.MkdirAll]
|
||||||
|
func MkdirAll(path string, perm os.FileMode) IOE.IOEither[error, string] {
|
||||||
|
return IOE.TryCatchError(func() (string, error) {
|
||||||
|
return path, os.MkdirAll(path, perm)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mkdir create a directory, see [os.Mkdir]
|
||||||
|
func Mkdir(path string, perm os.FileMode) IOE.IOEither[error, string] {
|
||||||
|
return IOE.TryCatchError(func() (string, error) {
|
||||||
|
return path, os.Mkdir(path, perm)
|
||||||
|
})
|
||||||
|
}
|
@@ -17,63 +17,74 @@ package generic
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
ET "github.com/IBM/fp-go/either"
|
ET "github.com/IBM/fp-go/either"
|
||||||
G "github.com/IBM/fp-go/internal/bindt"
|
A "github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bind applies a function to an input state and merges the result into that state
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
func Bind[
|
func Do[GS ~func() ET.Either[E, S], E, S any](
|
||||||
GS1 ~func() ET.Either[E, S1],
|
empty S,
|
||||||
GS2 ~func() ET.Either[E, S2],
|
) GS {
|
||||||
GA ~func() ET.Either[E, A],
|
return Of[GS, E, S](empty)
|
||||||
FCT ~func(S1) GA,
|
}
|
||||||
E any,
|
|
||||||
SET ~func(A) func(S1) S2,
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
A, S1, S2 any](s SET, f FCT) func(GS1) GS2 {
|
func Bind[GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], GT ~func() ET.Either[E, T], E, S1, S2, T any](
|
||||||
return G.Bind(
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
Chain[GS1, GS2, E, S1, S2],
|
Chain[GS1, GS2, E, S1, S2],
|
||||||
Map[GA, GS2, E, A, S2],
|
Map[GT, GS2, E, T, S2],
|
||||||
s,
|
setter,
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BindTo initializes some state based on a value
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
func BindTo[
|
func Let[GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], E, S1, S2, T any](
|
||||||
GS2 ~func() ET.Either[E, S2],
|
key func(T) func(S1) S2,
|
||||||
GA ~func() ET.Either[E, A],
|
f func(S1) T,
|
||||||
E any,
|
|
||||||
SET ~func(A) S2,
|
|
||||||
A, S2 any](s SET) func(GA) GS2 {
|
|
||||||
return G.BindTo(
|
|
||||||
Map[GA, GS2, E, A, S2],
|
|
||||||
s,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func ApS[
|
|
||||||
GS1 ~func() ET.Either[E, S1],
|
|
||||||
GS2 ~func() ET.Either[E, S2],
|
|
||||||
GB ~func() ET.Either[E, B],
|
|
||||||
GS1S2 ~func() ET.Either[E, func(S1) S2],
|
|
||||||
SET ~func(B) func(S1) S2,
|
|
||||||
E, S1, S2, B any,
|
|
||||||
](s SET, fb GB) func(GS1) GS2 {
|
|
||||||
return G.ApS[SET, S1, S2, B, GS1S2, GS1, GS2, GB](
|
|
||||||
Ap[GS2, GS1S2, GS1, E, S1, S2],
|
|
||||||
Map[GB, GS1S2, E, B, func(S1) S2],
|
|
||||||
s,
|
|
||||||
fb,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
func Let[
|
|
||||||
GS1 ~func() ET.Either[E, S1],
|
|
||||||
GS2 ~func() ET.Either[E, S2],
|
|
||||||
SET ~func(B) func(S1) S2,
|
|
||||||
FCT ~func(S1) B,
|
|
||||||
E, S1, S2, B any](
|
|
||||||
s SET,
|
|
||||||
f FCT,
|
|
||||||
) func(GS1) GS2 {
|
) func(GS1) GS2 {
|
||||||
return G.Let[SET, FCT, S1, S2, B, GS1, GS2](Map[GS1, GS2, E, S1, S2], s, f)
|
return F.Let(
|
||||||
|
Map[GS1, GS2, E, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], E, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, E, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func() ET.Either[E, S1], GT ~func() ET.Either[E, T], E, S1, S2, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, E, T, S1],
|
||||||
|
setter,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently
|
||||||
|
func ApS[GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], GT ~func() ET.Either[E, T], E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GS2, func() ET.Either[E, func(T) S2], GT, E, T, S2],
|
||||||
|
Map[GS1, func() ET.Either[E, func(T) S2], E, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
@@ -26,7 +26,7 @@ func Eq[GA ~func() ET.Either[E, A], E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[G
|
|||||||
return G.Eq[GA](eq)
|
return G.Eq[GA](eq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[GA ~func() ET.Either[E, A], E, A comparable]() EQ.Eq[GA] {
|
func FromStrictEquals[GA ~func() ET.Either[E, A], E, A comparable]() EQ.Eq[GA] {
|
||||||
return Eq[GA](ET.FromStrictEquals[E, A]())
|
return Eq[GA](ET.FromStrictEquals[E, A]())
|
||||||
}
|
}
|
||||||
|
@@ -87,7 +87,7 @@ func MonadMap[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B an
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Map[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) B) func(GA) GB {
|
func Map[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) B) func(GA) GB {
|
||||||
return F.Bind2nd(MonadMap[GA, GB, E, A, B], f)
|
return eithert.Map(IO.Map[GA, GB, ET.Either[E, A], ET.Either[E, B]], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadMapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, b B) GB {
|
func MonadMapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, b B) GB {
|
||||||
@@ -95,7 +95,7 @@ func MonadMapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](b B) func(GA) GB {
|
func MapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](b B) func(GA) GB {
|
||||||
return F.Bind2nd(MonadMapTo[GA, GB, E, A, B], b)
|
return Map[GA, GB](F.Constant1[A](b))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) GB) GB {
|
func MonadChain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) GB) GB {
|
||||||
@@ -103,7 +103,7 @@ func MonadChain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Chain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GB {
|
func Chain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GB {
|
||||||
return F.Bind2nd(MonadChain[GA, GB, E, A, B], f)
|
return eithert.Chain(IO.Chain[GA, GB, ET.Either[E, A], ET.Either[E, B]], IO.Of[GB, ET.Either[E, B]], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, fb GB) GB {
|
func MonadChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, fb GB) GB {
|
||||||
@@ -111,7 +111,7 @@ func MonadChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fb GB) func(GA) GB {
|
func ChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fb GB) func(GA) GB {
|
||||||
return F.Bind2nd(MonadChainTo[GA, GB, E, A, B], fb)
|
return Chain[GA, GB, E, A, B](F.Constant1[A](fb))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) ET.Either[E, B]) GB {
|
func MonadChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) ET.Either[E, B]) GB {
|
||||||
@@ -134,14 +134,18 @@ func MonadChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~f
|
|||||||
|
|
||||||
func ChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](f func(A) GR) func(GA) GB {
|
func ChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](f func(A) GR) func(GA) GB {
|
||||||
return FI.ChainIOK(
|
return FI.ChainIOK(
|
||||||
MonadChain[GA, GB, E, A, B],
|
Chain[GA, GB, E, A, B],
|
||||||
FromIO[GB, GR, E, B],
|
FromIO[GB, GR, E, B],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GB {
|
func ChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GB {
|
||||||
return F.Bind2nd(MonadChainEitherK[GA, GB, E, A, B], f)
|
return FE.ChainEitherK(
|
||||||
|
Chain[GA, GB, E, A, B],
|
||||||
|
FromEither[GB, E, B],
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadAp[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
func MonadAp[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
||||||
@@ -152,7 +156,10 @@ func MonadAp[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Ap[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
func Ap[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
||||||
return F.Bind2nd(MonadAp[GB, GAB, GA], ma)
|
return eithert.Ap(
|
||||||
|
IO.Ap[GB, func() func(ET.Either[E, A]) ET.Either[E, B], GA, ET.Either[E, B], ET.Either[E, A]],
|
||||||
|
IO.Map[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
|
||||||
|
ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
func MonadApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
||||||
@@ -163,7 +170,10 @@ func MonadApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B],
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
func ApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
||||||
return F.Bind2nd(MonadApSeq[GB, GAB, GA], ma)
|
return eithert.Ap(
|
||||||
|
IO.ApSeq[GB, func() func(ET.Either[E, A]) ET.Either[E, B], GA, ET.Either[E, B], ET.Either[E, A]],
|
||||||
|
IO.Map[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
|
||||||
|
ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
func MonadApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB {
|
||||||
@@ -174,7 +184,10 @@ func MonadApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B],
|
|||||||
}
|
}
|
||||||
|
|
||||||
func ApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
func ApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB {
|
||||||
return F.Bind2nd(MonadApPar[GB, GAB, GA], ma)
|
return eithert.Ap(
|
||||||
|
IO.ApPar[GB, func() func(ET.Either[E, A]) ET.Either[E, B], GA, ET.Either[E, B], ET.Either[E, A]],
|
||||||
|
IO.Map[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]],
|
||||||
|
ma)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any](mma GAA) GA {
|
func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any](mma GAA) GA {
|
||||||
@@ -200,11 +213,18 @@ func Memoize[GA ~func() ET.Either[E, A], E, A any](ma GA) GA {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func MonadMapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](fa GA1, f func(E1) E2) GA2 {
|
func MonadMapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](fa GA1, f func(E1) E2) GA2 {
|
||||||
return eithert.MonadMapLeft(IO.MonadMap[GA1, GA2, ET.Either[E1, A], ET.Either[E2, A]], fa, f)
|
return eithert.MonadMapLeft(
|
||||||
|
IO.MonadMap[GA1, GA2, ET.Either[E1, A], ET.Either[E2, A]],
|
||||||
|
fa,
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](f func(E1) E2) func(GA1) GA2 {
|
func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](f func(E1) E2) func(GA1) GA2 {
|
||||||
return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f)
|
return eithert.MapLeft(
|
||||||
|
IO.Map[GA1, GA2, ET.Either[E1, A], ET.Either[E2, A]],
|
||||||
|
f,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay creates an operation that passes in the value after some [time.Duration]
|
// Delay creates an operation that passes in the value after some [time.Duration]
|
||||||
@@ -223,7 +243,7 @@ func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2
|
|||||||
|
|
||||||
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
|
// BiMap maps a pair of functions over the two type arguments of the bifunctor.
|
||||||
func BiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB {
|
func BiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB {
|
||||||
return eithert.BiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], f, g)
|
return eithert.BiMap(IO.Map[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], f, g)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fold convers an IOEither into an IO
|
// Fold convers an IOEither into an IO
|
||||||
@@ -253,8 +273,8 @@ func MonadChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E,
|
|||||||
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
// ChainFirst runs the monad returned by the function but returns the result of the original monad
|
||||||
func ChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GA {
|
func ChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GA {
|
||||||
return C.ChainFirst(
|
return C.ChainFirst(
|
||||||
MonadChain[GA, GA, E, A, A],
|
Chain[GA, GA, E, A, A],
|
||||||
MonadMap[GB, GA, E, B, A],
|
Map[GB, GA, E, B, A],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -273,8 +293,8 @@ func MonadChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any]
|
|||||||
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad
|
||||||
func ChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GA) GA {
|
func ChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GA) GA {
|
||||||
return FI.ChainFirstIOK(
|
return FI.ChainFirstIOK(
|
||||||
MonadChain[GA, GA, E, A, A],
|
Chain[GA, GA, E, A, A],
|
||||||
MonadMap[func() ET.Either[E, B], GA, E, B, A],
|
Map[func() ET.Either[E, B], GA, E, B, A],
|
||||||
FromIO[func() ET.Either[E, B], GIOB, E, B],
|
FromIO[func() ET.Either[E, B], GIOB, E, B],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
@@ -294,8 +314,8 @@ func MonadChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](first GA, f
|
|||||||
// ChainFirstEitherK runs the monad returned by the function but returns the result of the original monad
|
// ChainFirstEitherK runs the monad returned by the function but returns the result of the original monad
|
||||||
func ChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GA {
|
func ChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GA {
|
||||||
return FE.ChainFirstEitherK(
|
return FE.ChainFirstEitherK(
|
||||||
MonadChain[GA, GA, E, A, A],
|
Chain[GA, GA, E, A, A],
|
||||||
MonadMap[func() ET.Either[E, B], GA, E, B, A],
|
Map[func() ET.Either[E, B], GA, E, B, A],
|
||||||
FromEither[func() ET.Either[E, B], E, B],
|
FromEither[func() ET.Either[E, B], E, B],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
@@ -339,7 +359,7 @@ func MonadFlap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B]
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 {
|
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)
|
return FC.Flap(Map[GEAB, GEB], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ToIOOption[GA ~func() O.Option[A], GEA ~func() ET.Either[E, A], E, A any](ioe GEA) GA {
|
func ToIOOption[GA ~func() O.Option[A], GEA ~func() ET.Either[E, A], E, A any](ioe GEA) GA {
|
||||||
|
@@ -24,9 +24,9 @@ import (
|
|||||||
F "github.com/IBM/fp-go/function"
|
F "github.com/IBM/fp-go/function"
|
||||||
)
|
)
|
||||||
|
|
||||||
// LogJson converts the argument to JSON and then logs it via the format string
|
// LogJSON converts the argument to JSON and then logs it via the format string
|
||||||
// Can be used with [ChainFirst]
|
// Can be used with [ChainFirst]
|
||||||
func LogJson[GA ~func() ET.Either[error, any], A any](prefix string) func(A) GA {
|
func LogJSON[GA ~func() ET.Either[error, any], A any](prefix string) func(A) GA {
|
||||||
return func(a A) GA {
|
return func(a A) GA {
|
||||||
// log this
|
// log this
|
||||||
return F.Pipe3(
|
return F.Pipe3(
|
||||||
@@ -41,3 +41,11 @@ func LogJson[GA ~func() ET.Either[error, any], A any](prefix string) func(A) GA
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LogJson converts the argument to JSON and then logs it via the format string
|
||||||
|
// Can be used with [ChainFirst]
|
||||||
|
//
|
||||||
|
// Deprecated: use [LogJSON] instead
|
||||||
|
func LogJson[GA ~func() ET.Either[error, any], A any](prefix string) func(A) GA {
|
||||||
|
return LogJSON[GA, A](prefix)
|
||||||
|
}
|
||||||
|
@@ -56,7 +56,7 @@ func Requester(builder *R.Builder) IOEH.Requester {
|
|||||||
return F.Pipe5(
|
return F.Pipe5(
|
||||||
builder.GetBody(),
|
builder.GetBody(),
|
||||||
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
O.Fold(LZ.Of(E.Of[error](withoutBody)), E.Map[error](withBody)),
|
||||||
E.Ap[func(string) IOE.IOEither[error, *http.Request]](builder.GetTargetUrl()),
|
E.Ap[func(string) IOE.IOEither[error, *http.Request]](builder.GetTargetURL()),
|
||||||
E.Flap[error, IOE.IOEither[error, *http.Request]](builder.GetMethod()),
|
E.Flap[error, IOE.IOEither[error, *http.Request]](builder.GetMethod()),
|
||||||
E.GetOrElse(IOE.Left[*http.Request, error]),
|
E.GetOrElse(IOE.Left[*http.Request, error]),
|
||||||
IOE.Map[error](func(req *http.Request) *http.Request {
|
IOE.Map[error](func(req *http.Request) *http.Request {
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user