mirror of
https://github.com/IBM/fp-go.git
synced 2025-06-21 00:19:34 +02:00
Add Do notation support and Bind to Monads (#100)
* fix: implement bind, let, apS for serveral monads Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: implement bind for maps Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: implement do notation for more monads Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: add bind to more monads Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> * fix: add Do and Bind support to Monads Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com> --------- Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
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"))
|
||||||
|
}
|
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,
|
||||||
|
)
|
||||||
|
}
|
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))
|
||||||
|
}
|
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"))
|
||||||
|
}
|
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,
|
||||||
|
)
|
||||||
|
}
|
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"))
|
||||||
|
}
|
@ -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]())
|
||||||
}
|
}
|
||||||
|
4
eq/eq.go
4
eq/eq.go
@ -35,12 +35,12 @@ 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}
|
||||||
}
|
}
|
||||||
|
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,
|
||||||
|
)
|
||||||
|
}
|
@ -37,6 +37,16 @@ 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 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 +117,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),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -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]),
|
|
||||||
))
|
|
||||||
}
|
|
@ -52,10 +52,59 @@ func ChainFirst[A, B, HKTA, HKTB any](
|
|||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -21,6 +21,54 @@ 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 F.Pipe2(
|
||||||
|
f,
|
||||||
|
gmap,
|
||||||
|
fmap,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
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 F.Pipe2(
|
||||||
|
b,
|
||||||
|
key,
|
||||||
|
mmap,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
@ -64,9 +64,6 @@ 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)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
)
|
||||||
|
}
|
@ -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]]()
|
||||||
}
|
}
|
||||||
|
@ -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]())
|
||||||
}
|
}
|
||||||
|
@ -134,7 +134,7 @@ 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,
|
||||||
)
|
)
|
||||||
|
66
iooption/bind.go
Normal file
66
iooption/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 iooption
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/iooption/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) IOOption[S] {
|
||||||
|
return G.Do[IOOption[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) IOOption[T],
|
||||||
|
) func(IOOption[S1]) IOOption[S2] {
|
||||||
|
return G.Bind[IOOption[S1], IOOption[S2], IOOption[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(IOOption[S1]) IOOption[S2] {
|
||||||
|
return G.Let[IOOption[S1], IOOption[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(IOOption[S1]) IOOption[S2] {
|
||||||
|
return G.LetTo[IOOption[S1], IOOption[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(IOOption[T]) IOOption[S1] {
|
||||||
|
return G.BindTo[IOOption[S1], IOOption[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 IOOption[T],
|
||||||
|
) func(IOOption[S1]) IOOption[S2] {
|
||||||
|
return G.ApS[IOOption[S1], IOOption[S2], IOOption[T], S1, S2, T](setter, fa)
|
||||||
|
}
|
57
iooption/bind_test.go
Normal file
57
iooption/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 iooption
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) IOOption[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) IOOption[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(), O.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(), O.Of("John Doe"))
|
||||||
|
}
|
31
iooption/eq.go
Normal file
31
iooption/eq.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package iooption
|
||||||
|
|
||||||
|
import (
|
||||||
|
EQ "github.com/IBM/fp-go/eq"
|
||||||
|
G "github.com/IBM/fp-go/iooption/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Eq implements the equals predicate for values contained in the IO monad
|
||||||
|
func Eq[A any](e EQ.Eq[A]) EQ.Eq[IOOption[A]] {
|
||||||
|
return G.Eq[IOOption[A]](e)
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
|
func FromStrictEquals[A comparable]() EQ.Eq[IOOption[A]] {
|
||||||
|
return G.FromStrictEquals[IOOption[A]]()
|
||||||
|
}
|
90
iooption/generic/bind.go
Normal file
90
iooption/generic/bind.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// 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"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~func() O.Option[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() O.Option[S1], GS2 ~func() O.Option[S2], GT ~func() O.Option[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() O.Option[S1], GS2 ~func() O.Option[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() O.Option[S1], GS2 ~func() O.Option[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() O.Option[S1], GT ~func() O.Option[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() O.Option[S1], GS2 ~func() O.Option[S2], GT ~func() O.Option[T], S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GS2, func() O.Option[func(T) S2], GT, T, S2],
|
||||||
|
Map[GS1, func() O.Option[func(T) S2], S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
32
iooption/generic/eq.go
Normal file
32
iooption/generic/eq.go
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
EQ "github.com/IBM/fp-go/eq"
|
||||||
|
G "github.com/IBM/fp-go/io/generic"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Eq implements the equals predicate for values contained in the IO monad
|
||||||
|
func Eq[GA ~func() O.Option[A], A any](e EQ.Eq[A]) EQ.Eq[GA] {
|
||||||
|
return G.Eq[GA](O.Eq(e))
|
||||||
|
}
|
||||||
|
|
||||||
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
|
func FromStrictEquals[GA ~func() O.Option[A], A comparable]() EQ.Eq[GA] {
|
||||||
|
return Eq[GA](EQ.FromStrictEquals[A]())
|
||||||
|
}
|
@ -145,7 +145,7 @@ func MonadChainIOK[GA ~func() O.Option[A], GB ~func() O.Option[B], GR ~func() B,
|
|||||||
|
|
||||||
func ChainIOK[GA ~func() O.Option[A], GB ~func() O.Option[B], GR ~func() B, A, B any](f func(A) GR) func(GA) GB {
|
func ChainIOK[GA ~func() O.Option[A], GB ~func() O.Option[B], GR ~func() B, A, B any](f func(A) GR) func(GA) GB {
|
||||||
return FI.ChainIOK(
|
return FI.ChainIOK(
|
||||||
MonadChain[GA, GB, A, B],
|
Chain[GA, GB, A, B],
|
||||||
FromIO[GB, GR, B],
|
FromIO[GB, GR, B],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
|
74
iooption/testing/laws.go
Normal file
74
iooption/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"
|
||||||
|
|
||||||
|
EQ "github.com/IBM/fp-go/eq"
|
||||||
|
L "github.com/IBM/fp-go/internal/monad/testing"
|
||||||
|
IOO "github.com/IBM/fp-go/iooption"
|
||||||
|
)
|
||||||
|
|
||||||
|
// AssertLaws asserts the apply monad laws for the `Either` 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,
|
||||||
|
IOO.Eq(eqa),
|
||||||
|
IOO.Eq(eqb),
|
||||||
|
IOO.Eq(eqc),
|
||||||
|
|
||||||
|
IOO.Of[A],
|
||||||
|
IOO.Of[B],
|
||||||
|
IOO.Of[C],
|
||||||
|
|
||||||
|
IOO.Of[func(A) A],
|
||||||
|
IOO.Of[func(A) B],
|
||||||
|
IOO.Of[func(B) C],
|
||||||
|
IOO.Of[func(func(A) B) B],
|
||||||
|
|
||||||
|
IOO.MonadMap[A, A],
|
||||||
|
IOO.MonadMap[A, B],
|
||||||
|
IOO.MonadMap[A, C],
|
||||||
|
IOO.MonadMap[B, C],
|
||||||
|
|
||||||
|
IOO.MonadMap[func(B) C, func(func(A) B) func(A) C],
|
||||||
|
|
||||||
|
IOO.MonadChain[A, A],
|
||||||
|
IOO.MonadChain[A, B],
|
||||||
|
IOO.MonadChain[A, C],
|
||||||
|
IOO.MonadChain[B, C],
|
||||||
|
|
||||||
|
IOO.MonadAp[A, A],
|
||||||
|
IOO.MonadAp[B, A],
|
||||||
|
IOO.MonadAp[C, B],
|
||||||
|
IOO.MonadAp[C, A],
|
||||||
|
|
||||||
|
IOO.MonadAp[B, func(A) B],
|
||||||
|
IOO.MonadAp[func(A) C, func(A) B],
|
||||||
|
|
||||||
|
ab,
|
||||||
|
bc,
|
||||||
|
)
|
||||||
|
|
||||||
|
}
|
47
iooption/testing/laws_test.go
Normal file
47
iooption/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))
|
||||||
|
}
|
66
iterator/stateless/bind.go
Normal file
66
iterator/stateless/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 stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/iterator/stateless/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S any](
|
||||||
|
empty S,
|
||||||
|
) Iterator[S] {
|
||||||
|
return G.Do[Iterator[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) Iterator[T],
|
||||||
|
) func(Iterator[S1]) Iterator[S2] {
|
||||||
|
return G.Bind[Iterator[S1], Iterator[S2], Iterator[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(Iterator[S1]) Iterator[S2] {
|
||||||
|
return G.Let[Iterator[S1], Iterator[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(Iterator[S1]) Iterator[S2] {
|
||||||
|
return G.LetTo[Iterator[S1], Iterator[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(Iterator[T]) Iterator[S1] {
|
||||||
|
return G.BindTo[Iterator[S1], Iterator[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 Iterator[T],
|
||||||
|
) func(Iterator[S1]) Iterator[S2] {
|
||||||
|
return G.ApS[Iterator[func(T) S2], Iterator[S1], Iterator[S2], Iterator[T], S1, S2, T](setter, fa)
|
||||||
|
}
|
57
iterator/stateless/bind_test.go
Normal file
57
iterator/stateless/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 stateless
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) Iterator[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Iterator[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, ToArray(res), A.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, ToArray(res), A.Of("John Doe"))
|
||||||
|
}
|
92
iterator/stateless/generic/bind.go
Normal file
92
iterator/stateless/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 (
|
||||||
|
"github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
O "github.com/IBM/fp-go/option"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~func() O.Option[T.Tuple2[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 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, S2, A any](
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
f func(S1) GA,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GS2, GS1, S1, S2],
|
||||||
|
Map[GS2, GA, func(A) S2, A, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], S1, S2, A any](
|
||||||
|
key func(A) func(S1) S2,
|
||||||
|
f func(S1) A,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS2, GS1, func(S1) S2, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS2, GS1, func(S1) S2, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, A any](
|
||||||
|
setter func(A) S1,
|
||||||
|
) func(GA) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GS1, GA, func(A) S1, A, 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[GAS2 ~func() O.Option[T.Tuple2[GAS2, func(A) S2]], GS1 ~func() O.Option[T.Tuple2[GS1, S1]], GS2 ~func() O.Option[T.Tuple2[GS2, S2]], GA ~func() O.Option[T.Tuple2[GA, A]], S1, S2, A any](
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
fa GA,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return apply.ApS(
|
||||||
|
Ap[GAS2, GS2, GA, A, S2],
|
||||||
|
Map[GAS2, GS1, func(S1) func(A) S2, S1, func(A) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
66
lazy/bind.go
Normal file
66
lazy/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 lazy
|
||||||
|
|
||||||
|
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,
|
||||||
|
) Lazy[S] {
|
||||||
|
return G.Do[Lazy[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) Lazy[T],
|
||||||
|
) func(Lazy[S1]) Lazy[S2] {
|
||||||
|
return G.Bind[Lazy[S1], Lazy[S2], Lazy[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(Lazy[S1]) Lazy[S2] {
|
||||||
|
return G.Let[Lazy[S1], Lazy[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(Lazy[S1]) Lazy[S2] {
|
||||||
|
return G.LetTo[Lazy[S1], Lazy[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(Lazy[T]) Lazy[S1] {
|
||||||
|
return G.BindTo[Lazy[S1], Lazy[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 Lazy[T],
|
||||||
|
) func(Lazy[S1]) Lazy[S2] {
|
||||||
|
return G.ApS[Lazy[S1], Lazy[S2], Lazy[T], S1, S2, T](setter, fa)
|
||||||
|
}
|
56
lazy/bind_test.go
Normal file
56
lazy/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 lazy
|
||||||
|
|
||||||
|
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) Lazy[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Lazy[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
option/bind.go
Normal file
89
option/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 option
|
||||||
|
|
||||||
|
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,
|
||||||
|
) Option[S] {
|
||||||
|
return Of(empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, A any](
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
f func(S1) Option[A],
|
||||||
|
) func(Option[S1]) Option[S2] {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[S1, S2],
|
||||||
|
Map[A, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
f func(S1) B,
|
||||||
|
) func(Option[S1]) Option[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(Option[S1]) Option[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(Option[T]) Option[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 Option[T],
|
||||||
|
) func(Option[S1]) Option[S2] {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[S2, T],
|
||||||
|
Map[S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
56
option/bind_test.go
Normal file
56
option/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 option
|
||||||
|
|
||||||
|
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) Option[string] {
|
||||||
|
return Of("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Option[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"))
|
||||||
|
}
|
@ -31,7 +31,7 @@ func Eq[A any](a EQ.Eq[A]) EQ.Eq[Option[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[A comparable]() EQ.Eq[Option[A]] {
|
func FromStrictEquals[A comparable]() EQ.Eq[Option[A]] {
|
||||||
return Eq(EQ.FromStrictEquals[A]())
|
return Eq(EQ.FromStrictEquals[A]())
|
||||||
}
|
}
|
||||||
|
66
reader/bind.go
Normal file
66
reader/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 reader
|
||||||
|
|
||||||
|
import (
|
||||||
|
G "github.com/IBM/fp-go/reader/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[R, S any](
|
||||||
|
empty S,
|
||||||
|
) Reader[R, S] {
|
||||||
|
return G.Do[Reader[R, S], R, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) Reader[R, T],
|
||||||
|
) func(Reader[R, S1]) Reader[R, S2] {
|
||||||
|
return G.Bind[Reader[R, S1], Reader[R, S2], Reader[R, T], R, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(Reader[R, S1]) Reader[R, S2] {
|
||||||
|
return G.Let[Reader[R, S1], Reader[R, S2], R, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(Reader[R, S1]) Reader[R, S2] {
|
||||||
|
return G.LetTo[Reader[R, S1], Reader[R, S2], R, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[R, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(Reader[R, T]) Reader[R, S1] {
|
||||||
|
return G.BindTo[Reader[R, S1], Reader[R, T], R, 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[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa Reader[R, T],
|
||||||
|
) func(Reader[R, S1]) Reader[R, S2] {
|
||||||
|
return G.ApS[Reader[R, S1], Reader[R, S2], Reader[R, T], R, S1, S2, T](setter, fa)
|
||||||
|
}
|
57
reader/bind_test.go
Normal file
57
reader/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 reader
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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) Reader[context.Context, string] {
|
||||||
|
return Of[context.Context]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Reader[context.Context, string] {
|
||||||
|
return Of[context.Context]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[context.Context](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), "John Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[context.Context]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[context.Context]("John")),
|
||||||
|
Map[context.Context](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), "John Doe")
|
||||||
|
}
|
89
reader/generic/bind.go
Normal file
89
reader/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(R) S, R, S any](
|
||||||
|
empty S,
|
||||||
|
) GS {
|
||||||
|
return Of[GS, R, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~func(R) S1, GS2 ~func(R) S2, GT ~func(R) T, R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GS1, GS2, R, S1, S2],
|
||||||
|
Map[GT, GS2, R, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~func(R) S1, GS2 ~func(R) S2, R, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS1, GS2, R, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func(R) S1, GS2 ~func(R) S2, R, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, R, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func(R) S1, GT ~func(R) T, R, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, R, 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(R) S1, GS2 ~func(R) S2, GT ~func(R) T, R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GT, GS2, func(R) func(T) S2, R, T, S2],
|
||||||
|
Map[GS1, func(R) func(T) S2, R, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
66
readereither/bind.go
Normal file
66
readereither/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 readereither
|
||||||
|
|
||||||
|
import (
|
||||||
|
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[R, E, S any](
|
||||||
|
empty S,
|
||||||
|
) ReaderEither[R, E, S] {
|
||||||
|
return G.Do[ReaderEither[R, E, S], R, E, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) ReaderEither[R, E, T],
|
||||||
|
) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2] {
|
||||||
|
return G.Bind[ReaderEither[R, E, S1], ReaderEither[R, E, S2], ReaderEither[R, E, T], R, E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2] {
|
||||||
|
return G.Let[ReaderEither[R, E, S1], ReaderEither[R, E, S2], R, E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2] {
|
||||||
|
return G.LetTo[ReaderEither[R, E, S1], ReaderEither[R, E, S2], R, E, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[R, E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(ReaderEither[R, E, T]) ReaderEither[R, E, S1] {
|
||||||
|
return G.BindTo[ReaderEither[R, E, S1], ReaderEither[R, E, T], R, 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[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa ReaderEither[R, E, T],
|
||||||
|
) func(ReaderEither[R, E, S1]) ReaderEither[R, E, S2] {
|
||||||
|
return G.ApS[ReaderEither[R, E, S1], ReaderEither[R, E, S2], ReaderEither[R, E, T], R, E, S1, S2, T](setter, fa)
|
||||||
|
}
|
58
readereither/bind_test.go
Normal file
58
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[context.Context, error, string] {
|
||||||
|
return Of[context.Context, error]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) ReaderEither[context.Context, error, string] {
|
||||||
|
return Of[context.Context, error]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context, error](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[context.Context, error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context, error](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[context.Context, error]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[context.Context, error]("John")),
|
||||||
|
Map[context.Context, error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background()), E.Of[error]("John Doe"))
|
||||||
|
}
|
90
readereither/generic/bind.go
Normal file
90
readereither/generic/bind.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
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(R) ET.Either[E, S], R, E, S any](
|
||||||
|
empty S,
|
||||||
|
) GS {
|
||||||
|
return Of[GS, E, R, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~func(R) ET.Either[E, S1], GS2 ~func(R) ET.Either[E, S2], GT ~func(R) ET.Either[E, T], R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
Chain[GS1, GS2, E, R, S1, S2],
|
||||||
|
Map[GT, GS2, E, R, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~func(R) ET.Either[E, S1], GS2 ~func(R) ET.Either[E, S2], R, E, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS1, GS2, E, R, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func(R) ET.Either[E, S1], GS2 ~func(R) ET.Either[E, S2], R, E, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, E, R, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func(R) ET.Either[E, S1], GT ~func(R) ET.Either[E, T], R, E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, E, R, 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(R) ET.Either[E, S1], GS2 ~func(R) ET.Either[E, S2], GT ~func(R) ET.Either[E, T], R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GT, GS2, func(R) ET.Either[E, func(T) S2], E, R, T, S2],
|
||||||
|
Map[GS1, func(R) ET.Either[E, func(T) S2], E, R, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@ -60,7 +60,7 @@ func MonadMap[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E,
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Map[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](f func(A) B) func(GEA) GEB {
|
func Map[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](f func(A) B) func(GEA) GEB {
|
||||||
return F.Bind2nd(MonadMap[GEA, GEB, L, E, A, B], f)
|
return readert.Map[GEA, GEB](ET.Map[L, A, B], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChain[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
func MonadChain[GEA ~func(E) ET.Either[L, A], GEB ~func(E) ET.Either[L, B], L, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
||||||
|
67
readerio/bind.go
Normal file
67
readerio/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 readerio
|
||||||
|
|
||||||
|
import (
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
|
G "github.com/IBM/fp-go/readerio/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[R, S any](
|
||||||
|
empty S,
|
||||||
|
) ReaderIO[R, S] {
|
||||||
|
return G.Do[ReaderIO[R, S], IO.IO[S], R, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) ReaderIO[R, T],
|
||||||
|
) func(ReaderIO[R, S1]) ReaderIO[R, S2] {
|
||||||
|
return G.Bind[ReaderIO[R, S1], ReaderIO[R, S2], ReaderIO[R, T], IO.IO[S1], IO.IO[S2], IO.IO[T], R, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(ReaderIO[R, S1]) ReaderIO[R, S2] {
|
||||||
|
return G.Let[ReaderIO[R, S1], ReaderIO[R, S2], IO.IO[S1], IO.IO[S2], R, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(ReaderIO[R, S1]) ReaderIO[R, S2] {
|
||||||
|
return G.LetTo[ReaderIO[R, S1], ReaderIO[R, S2], IO.IO[S1], IO.IO[S2], R, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[R, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(ReaderIO[R, T]) ReaderIO[R, S1] {
|
||||||
|
return G.BindTo[ReaderIO[R, S1], ReaderIO[R, T], IO.IO[S1], IO.IO[T], R, 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[R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa ReaderIO[R, T],
|
||||||
|
) func(ReaderIO[R, S1]) ReaderIO[R, S2] {
|
||||||
|
return G.ApS[ReaderIO[R, func(T) S2], ReaderIO[R, S1], ReaderIO[R, S2], ReaderIO[R, T], IO.IO[func(T) S2], IO.IO[S1], IO.IO[S2], IO.IO[T], R, S1, S2, T](setter, fa)
|
||||||
|
}
|
57
readerio/bind_test.go
Normal file
57
readerio/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 readerio
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"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) ReaderIO[context.Context, string] {
|
||||||
|
return Of[context.Context]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) ReaderIO[context.Context, string] {
|
||||||
|
return Of[context.Context]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[context.Context](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), "John Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[context.Context]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[context.Context]("John")),
|
||||||
|
Map[context.Context](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), "John Doe")
|
||||||
|
}
|
89
readerio/generic/bind.go
Normal file
89
readerio/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[GRS ~func(R) GS, GS ~func() S, R, S any](
|
||||||
|
empty S,
|
||||||
|
) GRS {
|
||||||
|
return Of[GRS, GS, R, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GRT ~func(R) GT, GS1 ~func() S1, GS2 ~func() S2, GT ~func() T, R, 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, R, S1, S2],
|
||||||
|
Map[GRT, GRS2, GT, GS2, R, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GS1 ~func() S1, GS2 ~func() S2, R, 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, R, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GS1 ~func() S1, GS2 ~func() S2, R, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GRS1, GRS2, GS1, GS2, R, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GRS1 ~func(R) GS1, GRT ~func(R) GT, GS1 ~func() S1, GT ~func() T, R, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GRT) GRS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GRT, GRS1, GT, GS1, R, 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(R) GTS1, GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GRT ~func(R) GT, GTS1 ~func() func(T) S2, GS1 ~func() S1, GS2 ~func() S2, GT ~func() T, R, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GRT,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GRT, GRS2, GRTS1, GT, GS2, GTS1, R, T, S2],
|
||||||
|
Map[GRS1, GRTS1, GS1, GTS1, R, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@ -40,7 +40,7 @@ func MonadMap[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func()
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Map[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) B) func(GEA) GEB {
|
func Map[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) B) func(GEA) GEB {
|
||||||
return F.Bind2nd(MonadMap[GEA, GEB, GIOA, GIOB, E, A, B], f)
|
return readert.Map[GEA, GEB](IO.Map[GIOA, GIOB, A, B], f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func MonadChain[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
func MonadChain[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](ma GEA, f func(A) GEB) GEB {
|
||||||
@ -97,7 +97,7 @@ func MonadChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~f
|
|||||||
|
|
||||||
func ChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEB {
|
func ChainIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEB {
|
||||||
return FIO.ChainIOK(
|
return FIO.ChainIOK(
|
||||||
MonadChain[GEA, GEB],
|
Chain[GEA, GEB],
|
||||||
FromIO[GEB],
|
FromIO[GEB],
|
||||||
f,
|
f,
|
||||||
)
|
)
|
||||||
|
67
readerioeither/bind.go
Normal file
67
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 (
|
||||||
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
|
G "github.com/IBM/fp-go/readerioeither/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[R, E, S any](
|
||||||
|
empty S,
|
||||||
|
) ReaderIOEither[R, E, S] {
|
||||||
|
return G.Do[ReaderIOEither[R, E, S], IOE.IOEither[E, S], R, E, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) ReaderIOEither[R, E, T],
|
||||||
|
) func(ReaderIOEither[R, E, S1]) ReaderIOEither[R, E, S2] {
|
||||||
|
return G.Bind[ReaderIOEither[R, E, S1], ReaderIOEither[R, E, S2], ReaderIOEither[R, E, T], IOE.IOEither[E, S1], IOE.IOEither[E, S2], IOE.IOEither[E, T], R, E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(ReaderIOEither[R, E, S1]) ReaderIOEither[R, E, S2] {
|
||||||
|
return G.Let[ReaderIOEither[R, E, S1], ReaderIOEither[R, E, S2], IOE.IOEither[E, S1], IOE.IOEither[E, S2], R, E, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(ReaderIOEither[R, E, S1]) ReaderIOEither[R, E, S2] {
|
||||||
|
return G.LetTo[ReaderIOEither[R, E, S1], ReaderIOEither[R, E, S2], IOE.IOEither[E, S1], IOE.IOEither[E, S2], R, E, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[R, E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(ReaderIOEither[R, E, T]) ReaderIOEither[R, E, S1] {
|
||||||
|
return G.BindTo[ReaderIOEither[R, E, S1], ReaderIOEither[R, E, T], IOE.IOEither[E, S1], IOE.IOEither[E, T], R, 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[R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa ReaderIOEither[R, E, T],
|
||||||
|
) func(ReaderIOEither[R, E, S1]) ReaderIOEither[R, E, S2] {
|
||||||
|
return G.ApS[ReaderIOEither[R, E, func(T) S2], ReaderIOEither[R, E, S1], ReaderIOEither[R, E, S2], ReaderIOEither[R, E, T], IOE.IOEither[E, func(T) S2], IOE.IOEither[E, S1], IOE.IOEither[E, S2], IOE.IOEither[E, T], R, E, S1, S2, T](setter, fa)
|
||||||
|
}
|
58
readerioeither/bind_test.go
Normal file
58
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[context.Context, error, string] {
|
||||||
|
return Of[context.Context, error]("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) ReaderIOEither[context.Context, error, string] {
|
||||||
|
return Of[context.Context, error]("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context, error](utils.Empty),
|
||||||
|
Bind(utils.SetLastName, getLastName),
|
||||||
|
Bind(utils.SetGivenName, getGivenName),
|
||||||
|
Map[context.Context, error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[context.Context, error](utils.Empty),
|
||||||
|
ApS(utils.SetLastName, Of[context.Context, error]("Doe")),
|
||||||
|
ApS(utils.SetGivenName, Of[context.Context, error]("John")),
|
||||||
|
Map[context.Context, error](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(context.Background())(), E.Of[error]("John Doe"))
|
||||||
|
}
|
@ -26,7 +26,7 @@ func Eq[R, E, A any](eq EQ.Eq[ET.Either[E, A]]) func(R) EQ.Eq[ReaderIOEither[R,
|
|||||||
return G.Eq[ReaderIOEither[R, E, A]](eq)
|
return G.Eq[ReaderIOEither[R, E, A]](eq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[R, E, A comparable]() func(R) EQ.Eq[ReaderIOEither[R, E, A]] {
|
func FromStrictEquals[R, E, A comparable]() func(R) EQ.Eq[ReaderIOEither[R, E, A]] {
|
||||||
return G.FromStrictEquals[ReaderIOEither[R, E, A]]()
|
return G.FromStrictEquals[ReaderIOEither[R, E, A]]()
|
||||||
}
|
}
|
||||||
|
90
readerioeither/generic/bind.go
Normal file
90
readerioeither/generic/bind.go
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
ET "github.com/IBM/fp-go/either"
|
||||||
|
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(R) GS, GS ~func() ET.Either[E, S], R, E, S any](
|
||||||
|
empty S,
|
||||||
|
) GRS {
|
||||||
|
return Of[GRS, GS, R, E, S](empty)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GRT ~func(R) GT, GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], GT ~func() ET.Either[E, T], R, E, 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, R, E, S1, S2],
|
||||||
|
Map[GRT, GRS2, GT, GS2, R, E, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], R, E, 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, R, E, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], R, E, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GRS1, GRS2, GS1, GS2, R, E, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GRS1 ~func(R) GS1, GRT ~func(R) GT, GS1 ~func() ET.Either[E, S1], GT ~func() ET.Either[E, T], R, E, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(GRT) GRS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GRT, GRS1, GT, GS1, R, 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[GRTS1 ~func(R) GTS1, GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GRT ~func(R) GT, GTS1 ~func() ET.Either[E, func(T) S2], GS1 ~func() ET.Either[E, S1], GS2 ~func() ET.Either[E, S2], GT ~func() ET.Either[E, T], R, E, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa GRT,
|
||||||
|
) func(GRS1) GRS2 {
|
||||||
|
return A.ApS(
|
||||||
|
Ap[GRT, GRS2, GRTS1, GT, GS2, GTS1, R, E, T, S2],
|
||||||
|
Map[GRS1, GRTS1, GS1, GTS1, R, E, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
@ -26,7 +26,7 @@ func Eq[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](eq EQ.Eq[E
|
|||||||
return G.Eq[GEA](eq)
|
return G.Eq[GEA](eq)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R any, E, A comparable]() func(R) EQ.Eq[GEA] {
|
func FromStrictEquals[GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R any, E, A comparable]() func(R) EQ.Eq[GEA] {
|
||||||
return Eq[GEA](ET.FromStrictEquals[E, A]())
|
return Eq[GEA](ET.FromStrictEquals[E, A]())
|
||||||
}
|
}
|
||||||
|
57
record/bind.go
Normal file
57
record/bind.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 record
|
||||||
|
|
||||||
|
import (
|
||||||
|
Mo "github.com/IBM/fp-go/monoid"
|
||||||
|
G "github.com/IBM/fp-go/record/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[K comparable, S any]() map[K]S {
|
||||||
|
return G.Do[map[K]S, K, S]()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, T any, K comparable, S2 any](m Mo.Monoid[map[K]S2]) func(setter func(T) func(S1) S2, f func(S1) map[K]T) func(map[K]S1) map[K]S2 {
|
||||||
|
return G.Bind[map[K]S1, map[K]S2, map[K]T, K, S1, S2, T](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[S1, T any, K comparable, S2 any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(map[K]S1) map[K]S2 {
|
||||||
|
return G.Let[map[K]S1, map[K]S2, K, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[S1, T any, K comparable, S2 any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(map[K]S1) map[K]S2 {
|
||||||
|
return G.LetTo[map[K]S1, map[K]S2, K, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[S1, T any, K comparable](setter func(T) S1) func(map[K]T) map[K]S1 {
|
||||||
|
return G.BindTo[map[K]S1, map[K]T, K, 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, T any, K comparable, S2 any](m Mo.Monoid[map[K]S2]) func(setter func(T) func(S1) S2, fa map[K]T) func(map[K]S1) map[K]S2 {
|
||||||
|
return G.ApS[map[K]S1, map[K]S2, map[K]T, K, S1, S2, T](m)
|
||||||
|
}
|
86
record/generic/bind.go
Normal file
86
record/generic/bind.go
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
// 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"
|
||||||
|
Mo "github.com/IBM/fp-go/monoid"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~map[K]S, K comparable, S any]() GS {
|
||||||
|
return Empty[GS, K, S]()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~map[K]S1, GS2 ~map[K]S2, GT ~map[K]T, K comparable, S1, S2, T any](m Mo.Monoid[GS2]) func(setter func(T) func(S1) S2, f func(S1) GT) func(GS1) GS2 {
|
||||||
|
c := Chain[GS1, GS2, K, S1, S2](m)
|
||||||
|
return func(setter func(T) func(S1) S2, f func(S1) GT) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
c,
|
||||||
|
Map[GT, GS2, K, T, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~map[K]S1, GS2 ~map[K]S2, K comparable, S1, S2, T any](
|
||||||
|
key func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS1, GS2, K, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~map[K]S1, GS2 ~map[K]S2, K comparable, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS1, GS2, K, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~map[K]S1, GT ~map[K]T, K comparable, S1, T any](setter func(T) S1) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GT, GS1, K, 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 ~map[K]S1, GS2 ~map[K]S2, GT ~map[K]T, K comparable, S1, S2, T any](m Mo.Monoid[GS2]) func(setter func(T) func(S1) S2, fa GT) func(GS1) GS2 {
|
||||||
|
a := Ap[GS2, map[K]func(T) S2, GT, K, S2, T](m)
|
||||||
|
return func(setter func(T) func(S1) S2, fa GT) func(GS1) GS2 {
|
||||||
|
return A.ApS(
|
||||||
|
a,
|
||||||
|
Map[GS1, map[K]func(T) S2, K, S1, func(T) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -132,6 +132,18 @@ func ReduceRefWithIndex[M ~map[K]V, K comparable, V, R any](f func(K, R, *V) R,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadAp[BS ~map[K]B, ABS ~map[K]func(A) B, AS ~map[K]A, K comparable, B, A any](m Mo.Monoid[BS], fab ABS, fa AS) BS {
|
||||||
|
return MonadChain(m, fab, F.Bind1st(MonadMap[AS, BS, K, A, B], fa))
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ap[BS ~map[K]B, ABS ~map[K]func(A) B, AS ~map[K]A, K comparable, B, A any](m Mo.Monoid[BS]) func(fa AS) func(ABS) BS {
|
||||||
|
return func(ma AS) func(ABS) BS {
|
||||||
|
return func(abs ABS) BS {
|
||||||
|
return MonadAp(m, abs, ma)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMap[M ~map[K]V, N ~map[K]R, K comparable, V, R any](r M, f func(V) R) N {
|
func MonadMap[M ~map[K]V, N ~map[K]R, K comparable, V, R any](r M, f func(V) R) N {
|
||||||
return MonadMapWithIndex[M, N](r, F.Ignore1of2[K](f))
|
return MonadMapWithIndex[M, N](r, F.Ignore1of2[K](f))
|
||||||
}
|
}
|
||||||
|
@ -333,3 +333,11 @@ func FromArray[
|
|||||||
V any](m Mg.Magma[V]) func(fa []T.Tuple2[K, V]) map[K]V {
|
V any](m Mg.Magma[V]) func(fa []T.Tuple2[K, V]) map[K]V {
|
||||||
return G.FromArray[[]T.Tuple2[K, V], map[K]V](m)
|
return G.FromArray[[]T.Tuple2[K, V], map[K]V](m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func MonadAp[A any, K comparable, B any](m Mo.Monoid[map[K]B], fab map[K]func(A) B, fa map[K]A) map[K]B {
|
||||||
|
return G.MonadAp[map[K]B, map[K]func(A) B, map[K]A](m, fab, fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Ap[A any, K comparable, B any](m Mo.Monoid[map[K]B]) func(fa map[K]A) func(map[K]func(A) B) map[K]B {
|
||||||
|
return G.Ap[map[K]B, map[K]func(A) B, map[K]A](m)
|
||||||
|
}
|
||||||
|
66
writer/bind.go
Normal file
66
writer/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 writer
|
||||||
|
|
||||||
|
import (
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
G "github.com/IBM/fp-go/writer/generic"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[S, W any](m M.Monoid[W]) func(S) Writer[W, S] {
|
||||||
|
return G.Do[Writer[W, S], W, S](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[S1, S2, T, W any](s S.Semigroup[W]) func(
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) Writer[W, T],
|
||||||
|
) func(Writer[W, S1]) Writer[W, S2] {
|
||||||
|
return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[W, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
f func(S1) T,
|
||||||
|
) func(Writer[W, S1]) Writer[W, S2] {
|
||||||
|
return G.Let[Writer[W, S1], Writer[W, S2], W, S1, S2, T](setter, f)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[W, S1, S2, T any](
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
b T,
|
||||||
|
) func(Writer[W, S1]) Writer[W, S2] {
|
||||||
|
return G.LetTo[Writer[W, S1], Writer[W, S2], W, S1, S2, T](setter, b)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[W, S1, T any](
|
||||||
|
setter func(T) S1,
|
||||||
|
) func(Writer[W, T]) Writer[W, S1] {
|
||||||
|
return G.BindTo[Writer[W, S1], Writer[W, T], W, 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, W any](s S.Semigroup[W]) func(
|
||||||
|
setter func(T) func(S1) S2,
|
||||||
|
fa Writer[W, T],
|
||||||
|
) func(Writer[W, S1]) Writer[W, S2] {
|
||||||
|
return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](s)
|
||||||
|
}
|
63
writer/bind_test.go
Normal file
63
writer/bind_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// 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 writer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
A "github.com/IBM/fp-go/array"
|
||||||
|
F "github.com/IBM/fp-go/function"
|
||||||
|
"github.com/IBM/fp-go/internal/utils"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
monoid = A.Monoid[string]()
|
||||||
|
sg = M.ToSemigroup(monoid)
|
||||||
|
)
|
||||||
|
|
||||||
|
func getLastName(s utils.Initial) Writer[[]string, string] {
|
||||||
|
return Of[string](monoid)("Doe")
|
||||||
|
}
|
||||||
|
|
||||||
|
func getGivenName(s utils.WithLastName) Writer[[]string, string] {
|
||||||
|
return Of[string](monoid)("John")
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBind(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[utils.Initial](monoid)(utils.Empty),
|
||||||
|
Bind[utils.Initial, utils.WithLastName, string](sg)(utils.SetLastName, getLastName),
|
||||||
|
Bind[utils.WithLastName, utils.WithGivenName, string](sg)(utils.SetGivenName, getGivenName),
|
||||||
|
Map[[]string](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), Of[string](monoid)("John Doe")())
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestApS(t *testing.T) {
|
||||||
|
|
||||||
|
res := F.Pipe3(
|
||||||
|
Do[utils.Initial](monoid)(utils.Empty),
|
||||||
|
ApS[utils.Initial, utils.WithLastName, string](sg)(utils.SetLastName, Of[string](monoid)("Doe")),
|
||||||
|
ApS[utils.WithLastName, utils.WithGivenName, string](sg)(utils.SetGivenName, Of[string](monoid)("John")),
|
||||||
|
Map[[]string](utils.GetFullName),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert.Equal(t, res(), Of[string](monoid)("John Doe")())
|
||||||
|
}
|
@ -25,7 +25,7 @@ func Eq[W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[Writer[W, A]] {
|
|||||||
return G.Eq[Writer[W, A]](w, a)
|
return G.Eq[Writer[W, A]](w, a)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[W, A comparable]() EQ.Eq[Writer[W, A]] {
|
func FromStrictEquals[W, A comparable]() EQ.Eq[Writer[W, A]] {
|
||||||
return G.FromStrictEquals[Writer[W, A]]()
|
return G.FromStrictEquals[Writer[W, A]]()
|
||||||
}
|
}
|
||||||
|
102
writer/generic/bind.go
Normal file
102
writer/generic/bind.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
// Copyright (c) 2023 IBM Corp.
|
||||||
|
// All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package generic
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/IBM/fp-go/internal/apply"
|
||||||
|
C "github.com/IBM/fp-go/internal/chain"
|
||||||
|
F "github.com/IBM/fp-go/internal/functor"
|
||||||
|
M "github.com/IBM/fp-go/monoid"
|
||||||
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
|
T "github.com/IBM/fp-go/tuple"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Bind creates an empty context of type [S] to be used with the [Bind] operation
|
||||||
|
func Do[GS ~func() T.Tuple2[S, W], W, S any](m M.Monoid[W]) func(S) GS {
|
||||||
|
return Of[GS, W, S](m)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bind attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Bind[GS1 ~func() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], GT ~func() T.Tuple2[A, W], W, S1, S2, A any](s S.Semigroup[W]) func(
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
ch := Chain[GS2, GS1, func(S1) GS2, W, S1, S2](s)
|
||||||
|
return func(
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
f func(S1) GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return C.Bind(
|
||||||
|
ch,
|
||||||
|
Map[GS2, GT, func(A) S2, W, A, S2],
|
||||||
|
setter,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Let attaches the result of a computation to a context [S1] to produce a context [S2]
|
||||||
|
func Let[GS1 ~func() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], W, S1, S2, A any](
|
||||||
|
key func(A) func(S1) S2,
|
||||||
|
f func(S1) A,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.Let(
|
||||||
|
Map[GS2, GS1, func(S1) S2, W, S1, S2],
|
||||||
|
key,
|
||||||
|
f,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LetTo attaches the a value to a context [S1] to produce a context [S2]
|
||||||
|
func LetTo[GS1 ~func() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], W, S1, S2, B any](
|
||||||
|
key func(B) func(S1) S2,
|
||||||
|
b B,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return F.LetTo(
|
||||||
|
Map[GS2, GS1, func(S1) S2, W, S1, S2],
|
||||||
|
key,
|
||||||
|
b,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// BindTo initializes a new state [S1] from a value [T]
|
||||||
|
func BindTo[GS1 ~func() T.Tuple2[S1, W], GT ~func() T.Tuple2[A, W], W, S1, A any](
|
||||||
|
setter func(A) S1,
|
||||||
|
) func(GT) GS1 {
|
||||||
|
return C.BindTo(
|
||||||
|
Map[GS1, GT, func(A) S1, W, A, 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() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], GT ~func() T.Tuple2[A, W], W, S1, S2, A any](s S.Semigroup[W]) func(
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
ap := Ap[GS2, func() T.Tuple2[func(A) S2, W], GT, W, A, S2](s)
|
||||||
|
return func(
|
||||||
|
setter func(A) func(S1) S2,
|
||||||
|
fa GT,
|
||||||
|
) func(GS1) GS2 {
|
||||||
|
return apply.ApS(
|
||||||
|
ap,
|
||||||
|
Map[func() T.Tuple2[func(A) S2, W], GS1, func(S1) func(A) S2],
|
||||||
|
setter,
|
||||||
|
fa,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
@ -30,7 +30,7 @@ func Eq[GA ~func() T.Tuple2[A, W], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// FromStrictEquals constructs an `Eq` from the canonical comparison function
|
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
|
||||||
func FromStrictEquals[GA ~func() T.Tuple2[A, W], W, A comparable]() EQ.Eq[GA] {
|
func FromStrictEquals[GA ~func() T.Tuple2[A, W], W, A comparable]() EQ.Eq[GA] {
|
||||||
return Eq[GA](EQ.FromStrictEquals[W](), EQ.FromStrictEquals[A]())
|
return Eq[GA](EQ.FromStrictEquals[W](), EQ.FromStrictEquals[A]())
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,22 @@ func Of[GA ~func() T.Tuple2[A, W], W, A any](m M.Monoid[W]) func(A) GA {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen modifies the result to include the changes to the accumulator
|
||||||
|
func Listen[GA ~func() T.Tuple2[A, W], GTA ~func() T.Tuple2[T.Tuple2[A, W], W], W, A any](fa GA) GTA {
|
||||||
|
return func() T.Tuple2[T.Tuple2[A, W], W] {
|
||||||
|
t := fa()
|
||||||
|
return T.MakeTuple2(T.MakeTuple2(t.F1, t.F2), t.F2)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass applies the returned function to the accumulator
|
||||||
|
func Pass[GFA ~func() T.Tuple2[T.Tuple2[A, FCT], W], GA ~func() T.Tuple2[A, W], FCT ~func(W) W, W, A any](fa GFA) GA {
|
||||||
|
return func() T.Tuple2[A, W] {
|
||||||
|
t := fa()
|
||||||
|
return T.MakeTuple2(t.F1.F1, t.F1.F2(t.F2))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMap[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
func MonadMap[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB {
|
||||||
return IO.MonadMap[GA, GB](fa, T.Map2(f, F.Identity[W]))
|
return IO.MonadMap[GA, GB](fa, T.Map2(f, F.Identity[W]))
|
||||||
}
|
}
|
||||||
|
@ -16,23 +16,35 @@
|
|||||||
package writer
|
package writer
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
EM "github.com/IBM/fp-go/endomorphism"
|
||||||
|
IO "github.com/IBM/fp-go/io"
|
||||||
M "github.com/IBM/fp-go/monoid"
|
M "github.com/IBM/fp-go/monoid"
|
||||||
S "github.com/IBM/fp-go/semigroup"
|
S "github.com/IBM/fp-go/semigroup"
|
||||||
T "github.com/IBM/fp-go/tuple"
|
T "github.com/IBM/fp-go/tuple"
|
||||||
G "github.com/IBM/fp-go/writer/generic"
|
G "github.com/IBM/fp-go/writer/generic"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Writer[W, A any] func() T.Tuple2[A, W]
|
type Writer[W, A any] IO.IO[T.Tuple2[A, W]]
|
||||||
|
|
||||||
func Of[A, W any](m M.Monoid[W]) func(A) Writer[W, A] {
|
func Of[A, W any](m M.Monoid[W]) func(A) Writer[W, A] {
|
||||||
return G.Of[Writer[W, A]](m)
|
return G.Of[Writer[W, A]](m)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Listen modifies the result to include the changes to the accumulator
|
||||||
|
func Listen[W, A any](fa Writer[W, A]) Writer[W, T.Tuple2[A, W]] {
|
||||||
|
return G.Listen[Writer[W, A], Writer[W, T.Tuple2[A, W]], W, A](fa)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Pass applies the returned function to the accumulator
|
||||||
|
func Pass[W, A any](fa Writer[W, T.Tuple2[A, EM.Endomorphism[W]]]) Writer[W, A] {
|
||||||
|
return G.Pass[Writer[W, T.Tuple2[A, EM.Endomorphism[W]]], Writer[W, A]](fa)
|
||||||
|
}
|
||||||
|
|
||||||
func MonadMap[FCT ~func(A) B, W, A, B any](fa Writer[W, A], f FCT) Writer[W, B] {
|
func MonadMap[FCT ~func(A) B, W, A, B any](fa Writer[W, A], f FCT) Writer[W, B] {
|
||||||
return G.MonadMap[Writer[W, B], Writer[W, A]](fa, f)
|
return G.MonadMap[Writer[W, B], Writer[W, A]](fa, f)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Map[FCT ~func(A) B, W, A, B any](f FCT) func(Writer[W, A]) Writer[W, B] {
|
func Map[W any, FCT ~func(A) B, A, B any](f FCT) func(Writer[W, A]) Writer[W, B] {
|
||||||
return G.Map[Writer[W, B], Writer[W, A]](f)
|
return G.Map[Writer[W, B], Writer[W, A]](f)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,10 +76,12 @@ func Flatten[W, A any](s S.Semigroup[W]) func(Writer[W, Writer[W, A]]) Writer[W,
|
|||||||
return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](s)
|
return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](s)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Execute extracts the accumulator
|
||||||
func Execute[W, A any](fa Writer[W, A]) W {
|
func Execute[W, A any](fa Writer[W, A]) W {
|
||||||
return G.Execute(fa)
|
return G.Execute(fa)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Evaluate extracts the value
|
||||||
func Evaluate[W, A any](fa Writer[W, A]) A {
|
func Evaluate[W, A any](fa Writer[W, A]) A {
|
||||||
return G.Evaluate(fa)
|
return G.Evaluate(fa)
|
||||||
}
|
}
|
||||||
|
@ -46,5 +46,4 @@ func ExampleWriter_logging() {
|
|||||||
fmt.Println(res())
|
fmt.Println(res())
|
||||||
|
|
||||||
// Output: Tuple2[int, []string](40, [Doubled 10 -> 20 Doubled 20 -> 40])
|
// Output: Tuple2[int, []string](40, [Doubled 10 -> 20 Doubled 20 -> 40])
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user