mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: add support for context sensitive readers
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
15
reader/array.go
Normal file
15
reader/array.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[R, A, B any](f func(A) Reader[R, B]) func([]A) Reader[R, []B] {
|
||||
return G.TraverseArray[Reader[R, B], Reader[R, []B], []A](f)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[R, A any](ma []Reader[R, A]) Reader[R, []A] {
|
||||
return G.SequenceArray[Reader[R, A], Reader[R, []A]](ma)
|
||||
}
|
25
reader/array_test.go
Normal file
25
reader/array_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
A "github.com/ibm/fp-go/array"
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSequenceArray(t *testing.T) {
|
||||
|
||||
n := 10
|
||||
|
||||
readers := A.MakeBy(n, Of[context.Context, int])
|
||||
exp := A.MakeBy(n, F.Identity[int])
|
||||
|
||||
g := F.Pipe1(
|
||||
readers,
|
||||
SequenceArray[context.Context, int],
|
||||
)
|
||||
|
||||
assert.Equal(t, exp, g(context.Background()))
|
||||
}
|
49
reader/curry.go
Normal file
49
reader/curry.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[R, A any](f func(R) A) Reader[R, A] {
|
||||
return G.Curry0[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry1[R, T1, A any](f func(R, T1) A) func(T1) Reader[R, A] {
|
||||
return G.Curry1[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry2[R, T1, T2, A any](f func(R, T1, T2) A) func(T1) func(T2) Reader[R, A] {
|
||||
return G.Curry2[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1) func(T2) func(T3) Reader[R, A] {
|
||||
return G.Curry3[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Curry4[R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1) func(T2) func(T3) func(T4) Reader[R, A] {
|
||||
return G.Curry4[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Uncurry0[R, A any](f Reader[R, A]) func(R) A {
|
||||
return G.Uncurry0(f)
|
||||
}
|
||||
|
||||
func Uncurry1[R, T1, A any](f func(T1) Reader[R, A]) func(R, T1) A {
|
||||
return G.Uncurry1(f)
|
||||
}
|
||||
|
||||
func Uncurry2[R, T1, T2, A any](f func(T1) func(T2) Reader[R, A]) func(R, T1, T2) A {
|
||||
return G.Uncurry2(f)
|
||||
}
|
||||
|
||||
func Uncurry3[R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) Reader[R, A]) func(R, T1, T2, T3) A {
|
||||
return G.Uncurry3(f)
|
||||
}
|
||||
|
||||
func Uncurry4[R, T1, T2, T3, T4, A any](f func(T1) func(T2) func(T3) func(T4) Reader[R, A]) func(R, T1, T2, T3, T4) A {
|
||||
return G.Uncurry4(f)
|
||||
}
|
25
reader/from.go
Normal file
25
reader/from.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
)
|
||||
|
||||
func From0[R, A any](f func(R) A) Reader[R, A] {
|
||||
return G.From0[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From1[R, T1, A any](f func(R, T1) A) func(T1) Reader[R, A] {
|
||||
return G.From1[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From2[R, T1, T2, A any](f func(R, T1, T2) A) func(T1, T2) Reader[R, A] {
|
||||
return G.From2[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From3[R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1, T2, T3) Reader[R, A] {
|
||||
return G.From3[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func From4[R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1, T2, T3, T4) Reader[R, A] {
|
||||
return G.From4[Reader[R, A]](f)
|
||||
}
|
31
reader/generic/array.go
Normal file
31
reader/generic/array.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
RA "github.com/ibm/fp-go/internal/array"
|
||||
)
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func MonadTraverseArray[GB ~func(R) B, GBS ~func(R) BBS, AAS ~[]A, BBS ~[]B, R, A, B any](tas AAS, f func(A) GB) GBS {
|
||||
return RA.MonadTraverse[AAS](
|
||||
Of[GBS, R, BBS],
|
||||
Map[GBS, func(R) func(B) BBS, R, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(R) func(B) BBS, R, B, BBS],
|
||||
tas, f,
|
||||
)
|
||||
}
|
||||
|
||||
// TraverseArray transforms an array
|
||||
func TraverseArray[GB ~func(R) B, GBS ~func(R) BBS, AAS ~[]A, BBS ~[]B, R, A, B any](f func(A) GB) func(AAS) GBS {
|
||||
return RA.Traverse[AAS](
|
||||
Of[GBS, R, BBS],
|
||||
Map[GBS, func(R) func(B) BBS, R, BBS, func(B) BBS],
|
||||
Ap[GB, GBS, func(R) func(B) BBS, R, B, BBS],
|
||||
f,
|
||||
)
|
||||
}
|
||||
|
||||
// SequenceArray converts a homogeneous sequence of either into an either of sequence
|
||||
func SequenceArray[GA ~func(R) A, GAS ~func(R) AAS, AAS ~[]A, GAAS ~[]GA, R, A any](ma GAAS) GAS {
|
||||
return MonadTraverseArray[GA, GAS](ma, F.Identity[GA])
|
||||
}
|
61
reader/generic/curry.go
Normal file
61
reader/generic/curry.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
)
|
||||
|
||||
// these functions curry a golang function with the context as the firsr parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func Curry0[GA ~func(R) A, R, A any](f func(R) A) GA {
|
||||
return MakeReader[GA](f)
|
||||
}
|
||||
|
||||
func Curry1[GA ~func(R) A, R, T1, A any](f func(R, T1) A) func(T1) GA {
|
||||
return F.Curry1(From1[GA](f))
|
||||
}
|
||||
|
||||
func Curry2[GA ~func(R) A, R, T1, T2, A any](f func(R, T1, T2) A) func(T1) func(T2) GA {
|
||||
return F.Curry2(From2[GA](f))
|
||||
}
|
||||
|
||||
func Curry3[GA ~func(R) A, R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1) func(T2) func(T3) GA {
|
||||
return F.Curry3(From3[GA](f))
|
||||
}
|
||||
|
||||
func Curry4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1) func(T2) func(T3) func(T4) GA {
|
||||
return F.Curry4(From4[GA](f))
|
||||
}
|
||||
|
||||
func Uncurry0[GA ~func(R) A, R, A any](f GA) func(R) A {
|
||||
return f
|
||||
}
|
||||
|
||||
func Uncurry1[GA ~func(R) A, R, T1, A any](f func(T1) GA) func(R, T1) A {
|
||||
uc := F.Uncurry1(f)
|
||||
return func(r R, t1 T1) A {
|
||||
return uc(t1)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry2[GA ~func(R) A, R, T1, T2, A any](f func(T1) func(T2) GA) func(R, T1, T2) A {
|
||||
uc := F.Uncurry2(f)
|
||||
return func(r R, t1 T1, t2 T2) A {
|
||||
return uc(t1, t2)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry3[GA ~func(R) A, R, T1, T2, T3, A any](f func(T1) func(T2) func(T3) GA) func(R, T1, T2, T3) A {
|
||||
uc := F.Uncurry3(f)
|
||||
return func(r R, t1 T1, t2 T2, t3 T3) A {
|
||||
return uc(t1, t2, t3)(r)
|
||||
}
|
||||
}
|
||||
|
||||
func Uncurry4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(T1) func(T2) func(T3) func(T4) GA) func(R, T1, T2, T3, T4) A {
|
||||
uc := F.Uncurry4(f)
|
||||
return func(r R, t1 T1, t2 T2, t3 T3, t4 T4) A {
|
||||
return uc(t1, t2, t3, t4)(r)
|
||||
}
|
||||
}
|
41
reader/generic/from.go
Normal file
41
reader/generic/from.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package generic
|
||||
|
||||
// these functions convert a golang function with the context as the first parameter into a reader with the context as the last parameter, which
|
||||
// is a equivalent to a function returning a reader of that context
|
||||
// this goes back to the advice in https://pkg.go.dev/context to put the context as a first parameter as a convention
|
||||
|
||||
func From0[GA ~func(R) A, R, A any](f func(R) A) GA {
|
||||
return MakeReader[GA](f)
|
||||
}
|
||||
|
||||
func From1[GA ~func(R) A, R, T1, A any](f func(R, T1) A) func(T1) GA {
|
||||
return func(t1 T1) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From2[GA ~func(R) A, R, T1, T2, A any](f func(R, T1, T2) A) func(T1, T2) GA {
|
||||
return func(t1 T1, t2 T2) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From3[GA ~func(R) A, R, T1, T2, T3, A any](f func(R, T1, T2, T3) A) func(T1, T2, T3) GA {
|
||||
return func(t1 T1, t2 T2, t3 T3) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2, t3)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func From4[GA ~func(R) A, R, T1, T2, T3, T4, A any](f func(R, T1, T2, T3, T4) A) func(T1, T2, T3, T4) GA {
|
||||
return func(t1 T1, t2 T2, t3 T3, t4 T4) GA {
|
||||
return MakeReader[GA](func(r R) A {
|
||||
return f(r, t1, t2, t3, t4)
|
||||
})
|
||||
}
|
||||
}
|
107
reader/generic/reader.go
Normal file
107
reader/generic/reader.go
Normal file
@@ -0,0 +1,107 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
F "github.com/ibm/fp-go/function"
|
||||
I "github.com/ibm/fp-go/identity/generic"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// Reader[R, A] = func(R) A
|
||||
|
||||
// MakeReader creates a reader, i.e. a method that accepts a context and that returns a value
|
||||
func MakeReader[GA ~func(R) A, R, A any](r GA) GA {
|
||||
return r
|
||||
}
|
||||
|
||||
// Ask reads the current context
|
||||
func Ask[GR ~func(R) R, R any]() GR {
|
||||
return MakeReader(F.Identity[R])
|
||||
}
|
||||
|
||||
// Asks projects a value from the global context in a Reader
|
||||
func Asks[GA ~func(R) A, R, A any](f GA) GA {
|
||||
return MakeReader(f)
|
||||
}
|
||||
|
||||
func AsksReader[GA ~func(R) A, R, A any](f func(R) GA) GA {
|
||||
return MakeReader(func(r R) A {
|
||||
return f(r)(r)
|
||||
})
|
||||
}
|
||||
|
||||
func MonadMap[GA ~func(E) A, GB ~func(E) B, E, A, B any](fa GA, f func(A) B) GB {
|
||||
return MakeReader(F.Flow2(fa, f))
|
||||
}
|
||||
|
||||
// Map can be used to turn functions `func(A)B` into functions `(fa F[A])F[B]` whose argument and return types
|
||||
// use the type constructor `F` to represent some computational context.
|
||||
func Map[GA ~func(E) A, GB ~func(E) B, E, A, B any](f func(A) B) func(GA) GB {
|
||||
return F.Bind2nd(MonadMap[GA, GB, E, A, B], f)
|
||||
}
|
||||
|
||||
func MonadAp[GA ~func(R) A, GB ~func(R) B, GAB ~func(R) func(A) B, R, A, B any](fab GAB, fa GA) GB {
|
||||
return MakeReader(func(r R) B {
|
||||
return fab(r)(fa(r))
|
||||
})
|
||||
}
|
||||
|
||||
// Ap applies a function to an argument under a type constructor.
|
||||
func Ap[GA ~func(R) A, GB ~func(R) B, GAB ~func(R) func(A) B, R, A, B any](fa GA) func(GAB) GB {
|
||||
return F.Bind2nd(MonadAp[GA, GB, GAB, R, A, B], fa)
|
||||
}
|
||||
|
||||
func Of[GA ~func(R) A, R, A any](a A) GA {
|
||||
return F.Constant1[R](a)
|
||||
}
|
||||
|
||||
func MonadChain[GA ~func(R) A, GB ~func(R) B, R, A, B any](ma GA, f func(A) GB) GB {
|
||||
return MakeReader(func(r R) B {
|
||||
return f(ma(r))(r)
|
||||
})
|
||||
}
|
||||
|
||||
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
|
||||
func Chain[GA ~func(R) A, GB ~func(R) B, R, A, B any](f func(A) GB) func(GA) GB {
|
||||
return F.Bind2nd(MonadChain[GA, GB, R, A, B], f)
|
||||
}
|
||||
|
||||
func Flatten[GA ~func(R) A, GGA ~func(R) GA, R, A any](mma GGA) GA {
|
||||
return MonadChain(mma, F.Identity[GA])
|
||||
}
|
||||
|
||||
func Compose[AB ~func(A) B, BC ~func(B) C, AC ~func(A) C, A, B, C any](ab AB) func(BC) AC {
|
||||
return func(bc BC) AC {
|
||||
return F.Flow2(ab, bc)
|
||||
}
|
||||
}
|
||||
|
||||
func First[GAB ~func(A) B, GABC ~func(T.Tuple2[A, C]) T.Tuple2[B, C], A, B, C any](pab GAB) GABC {
|
||||
return MakeReader(func(tac T.Tuple2[A, C]) T.Tuple2[B, C] {
|
||||
return T.MakeTuple2(pab(tac.F1), tac.F2)
|
||||
})
|
||||
}
|
||||
|
||||
func Second[GBC ~func(B) C, GABC ~func(T.Tuple2[A, B]) T.Tuple2[A, C], A, B, C any](pbc GBC) GABC {
|
||||
return MakeReader(func(tab T.Tuple2[A, B]) T.Tuple2[A, C] {
|
||||
return T.MakeTuple2(tab.F1, pbc(tab.F2))
|
||||
})
|
||||
}
|
||||
|
||||
func Promap[GA ~func(E) A, GB ~func(D) B, E, A, D, B any](f func(D) E, g func(A) B) func(GA) GB {
|
||||
return func(fea GA) GB {
|
||||
return MakeReader(F.Flow3(f, fea, g))
|
||||
}
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[GA1 ~func(R1) A, GA2 ~func(R2) A, R2, R1, A any](f func(R2) R1) func(GA1) GA2 {
|
||||
return func(r1 GA1) GA2 {
|
||||
return F.Flow2(f, r1)
|
||||
}
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[GA ~func(E) A, E, A any](e E) func(GA) A {
|
||||
return I.Ap[GA](e)
|
||||
}
|
46
reader/generic/sequence.go
Normal file
46
reader/generic/sequence.go
Normal file
@@ -0,0 +1,46 @@
|
||||
package generic
|
||||
|
||||
import (
|
||||
"github.com/ibm/fp-go/internal/apply"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[GA ~func(R) A, GTA ~func(R) T.Tuple1[A], R, A any](a GA) GTA {
|
||||
return apply.SequenceT1(
|
||||
Map[GA, GTA, R, A, T.Tuple1[A]],
|
||||
|
||||
a,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT2[GA ~func(R) A, GB ~func(R) B, GTAB ~func(R) T.Tuple2[A, B], R, A, B any](a GA, b GB) GTAB {
|
||||
return apply.SequenceT2(
|
||||
Map[GA, func(R) func(B) T.Tuple2[A, B], R, A, func(B) T.Tuple2[A, B]],
|
||||
Ap[GB, GTAB, func(R) func(B) T.Tuple2[A, B], R, B, T.Tuple2[A, B]],
|
||||
|
||||
a, b,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT3[GA ~func(R) A, GB ~func(R) B, GC ~func(R) C, GTABC ~func(R) T.Tuple3[A, B, C], R, A, B, C any](a GA, b GB, c GC) GTABC {
|
||||
return apply.SequenceT3(
|
||||
Map[GA, func(R) func(B) func(C) T.Tuple3[A, B, C], R, A, func(B) func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GB, func(R) func(C) T.Tuple3[A, B, C], func(R) func(B) func(C) T.Tuple3[A, B, C], R, B, func(C) T.Tuple3[A, B, C]],
|
||||
Ap[GC, GTABC, func(R) func(C) T.Tuple3[A, B, C], R, C, T.Tuple3[A, B, C]],
|
||||
|
||||
a, b, c,
|
||||
)
|
||||
}
|
||||
|
||||
func SequenceT4[GA ~func(R) A, GB ~func(R) B, GC ~func(R) C, GD ~func(R) D, GTABCD ~func(R) T.Tuple4[A, B, C, D], R, A, B, C, D any](a GA, b GB, c GC, d GD) GTABCD {
|
||||
return apply.SequenceT4(
|
||||
Map[GA, func(R) func(B) func(C) func(D) T.Tuple4[A, B, C, D], R, A, func(B) func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GB, func(R) func(C) func(D) T.Tuple4[A, B, C, D], func(R) func(B) func(C) func(D) T.Tuple4[A, B, C, D], R, B, func(C) func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GC, func(R) func(D) T.Tuple4[A, B, C, D], func(R) func(C) func(D) T.Tuple4[A, B, C, D], R, C, func(D) T.Tuple4[A, B, C, D]],
|
||||
Ap[GD, GTABCD, func(R) func(D) T.Tuple4[A, B, C, D], R, D, T.Tuple4[A, B, C, D]],
|
||||
|
||||
a, b, c, d,
|
||||
)
|
||||
}
|
92
reader/reader.go
Normal file
92
reader/reader.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// The purpose of the `Reader` monad is to avoid threading arguments through multiple functions in order to only get them where they are needed.
|
||||
// The first template argument `R` is the the context to read from, the second argument `A` is the return value of the monad
|
||||
type Reader[R, A any] func(R) A
|
||||
|
||||
// MakeReader creates a reader, i.e. a method that accepts a context and that returns a value
|
||||
func MakeReader[R, A any](r Reader[R, A]) Reader[R, A] {
|
||||
return G.MakeReader(r)
|
||||
}
|
||||
|
||||
// Ask reads the current context
|
||||
func Ask[R any]() Reader[R, R] {
|
||||
return G.Ask[Reader[R, R]]()
|
||||
}
|
||||
|
||||
// Asks projects a value from the global context in a Reader
|
||||
func Asks[R, A any](f Reader[R, A]) Reader[R, A] {
|
||||
return G.Asks(f)
|
||||
}
|
||||
|
||||
func AsksReader[R, A any](f func(R) Reader[R, A]) Reader[R, A] {
|
||||
return G.AsksReader(f)
|
||||
}
|
||||
|
||||
func MonadMap[E, A, B any](fa Reader[E, A], f func(A) B) Reader[E, B] {
|
||||
return G.MonadMap[Reader[E, A], Reader[E, B]](fa, f)
|
||||
}
|
||||
|
||||
// Map can be used to turn functions `func(A)B` into functions `(fa F[A])F[B]` whose argument and return types
|
||||
// use the type constructor `F` to represent some computational context.
|
||||
func Map[E, A, B any](f func(A) B) func(Reader[E, A]) Reader[E, B] {
|
||||
return G.Map[Reader[E, A], Reader[E, B]](f)
|
||||
}
|
||||
|
||||
func MonadAp[B, R, A any](fab Reader[R, func(A) B], fa Reader[R, A]) Reader[R, B] {
|
||||
return G.MonadAp[Reader[R, A], Reader[R, B]](fab, fa)
|
||||
}
|
||||
|
||||
// Ap applies a function to an argument under a type constructor.
|
||||
func Ap[B, R, A any](fa Reader[R, A]) func(Reader[R, func(A) B]) Reader[R, B] {
|
||||
return G.Ap[Reader[R, A], Reader[R, B], Reader[R, func(A) B]](fa)
|
||||
}
|
||||
|
||||
func Of[R, A any](a A) Reader[R, A] {
|
||||
return G.Of[Reader[R, A]](a)
|
||||
}
|
||||
|
||||
func MonadChain[R, A, B any](ma Reader[R, A], f func(A) Reader[R, B]) Reader[R, B] {
|
||||
return G.MonadChain(ma, f)
|
||||
}
|
||||
|
||||
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
|
||||
func Chain[R, A, B any](f func(A) Reader[R, B]) func(Reader[R, A]) Reader[R, B] {
|
||||
return G.Chain[Reader[R, A]](f)
|
||||
}
|
||||
|
||||
func Flatten[R, A any](mma func(R) Reader[R, A]) Reader[R, A] {
|
||||
return G.Flatten(mma)
|
||||
}
|
||||
|
||||
func Compose[R, B, C any](ab Reader[R, B]) func(Reader[B, C]) Reader[R, C] {
|
||||
return G.Compose[Reader[R, B], Reader[B, C], Reader[R, C]](ab)
|
||||
}
|
||||
|
||||
func First[A, B, C any](pab Reader[A, B]) Reader[T.Tuple2[A, C], T.Tuple2[B, C]] {
|
||||
return G.First[Reader[A, B], Reader[T.Tuple2[A, C], T.Tuple2[B, C]]](pab)
|
||||
}
|
||||
|
||||
func Second[A, B, C any](pbc Reader[B, C]) Reader[T.Tuple2[A, B], T.Tuple2[A, C]] {
|
||||
return G.Second[Reader[B, C], Reader[T.Tuple2[A, B], T.Tuple2[A, C]]](pbc)
|
||||
}
|
||||
|
||||
func Promap[E, A, D, B any](f func(D) E, g func(A) B) func(Reader[E, A]) Reader[D, B] {
|
||||
return G.Promap[Reader[E, A], Reader[D, B]](f, g)
|
||||
}
|
||||
|
||||
// Local changes the value of the local context during the execution of the action `ma` (similar to `Contravariant`'s
|
||||
// `contramap`).
|
||||
func Local[R2, R1, A any](f func(R2) R1) func(Reader[R1, A]) Reader[R2, A] {
|
||||
return G.Local[Reader[R1, A], Reader[R2, A]](f)
|
||||
}
|
||||
|
||||
// Read applies a context to a reader to obtain its value
|
||||
func Read[E, A any](e E) func(Reader[E, A]) A {
|
||||
return G.Read[Reader[E, A]](e)
|
||||
}
|
19
reader/reader_test.go
Normal file
19
reader/reader_test.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
F "github.com/ibm/fp-go/function"
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/ibm/fp-go/internal/utils"
|
||||
)
|
||||
|
||||
func TestMap(t *testing.T) {
|
||||
|
||||
assert.Equal(t, 2, F.Pipe1(Of[string](1), Map[string](utils.Double))(""))
|
||||
}
|
||||
|
||||
func TestAp(t *testing.T) {
|
||||
assert.Equal(t, 2, F.Pipe1(Of[int](utils.Double), Ap[int, int, int](Of[int](1)))(0))
|
||||
}
|
25
reader/semigroup.go
Normal file
25
reader/semigroup.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
M "github.com/ibm/fp-go/monoid"
|
||||
S "github.com/ibm/fp-go/semigroup"
|
||||
)
|
||||
|
||||
func ApplySemigroup[R, A any](
|
||||
_map func(func(R) A, func(A) func(A) A) func(R, func(A) A),
|
||||
_ap func(func(R, func(A) A), func(R) A) func(R) A,
|
||||
|
||||
s S.Semigroup[A],
|
||||
) S.Semigroup[func(R) A] {
|
||||
return S.ApplySemigroup(_map, _ap, s)
|
||||
}
|
||||
|
||||
func ApplicativeMonoid[R, A any](
|
||||
_of func(A) func(R) A,
|
||||
_map func(func(R) A, func(A) func(A) A) func(R, func(A) A),
|
||||
_ap func(func(R, func(A) A), func(R) A) func(R) A,
|
||||
|
||||
m M.Monoid[A],
|
||||
) M.Monoid[func(R) A] {
|
||||
return M.ApplicativeMonoid(_of, _map, _ap, m)
|
||||
}
|
24
reader/sequence.go
Normal file
24
reader/sequence.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package reader
|
||||
|
||||
import (
|
||||
G "github.com/ibm/fp-go/reader/generic"
|
||||
T "github.com/ibm/fp-go/tuple"
|
||||
)
|
||||
|
||||
// SequenceT converts n inputs of higher kinded types into a higher kinded types of n strongly typed values, represented as a tuple
|
||||
|
||||
func SequenceT1[R, A any](a Reader[R, A]) Reader[R, T.Tuple1[A]] {
|
||||
return G.SequenceT1[Reader[R, A], Reader[R, T.Tuple1[A]]](a)
|
||||
}
|
||||
|
||||
func SequenceT2[R, A, B any](a Reader[R, A], b Reader[R, B]) Reader[R, T.Tuple2[A, B]] {
|
||||
return G.SequenceT2[Reader[R, A], Reader[R, B], Reader[R, T.Tuple2[A, B]]](a, b)
|
||||
}
|
||||
|
||||
func SequenceT3[R, A, B, C any](a Reader[R, A], b Reader[R, B], c Reader[R, C]) Reader[R, T.Tuple3[A, B, C]] {
|
||||
return G.SequenceT3[Reader[R, A], Reader[R, B], Reader[R, C], Reader[R, T.Tuple3[A, B, C]]](a, b, c)
|
||||
}
|
||||
|
||||
func SequenceT4[R, A, B, C, D any](a Reader[R, A], b Reader[R, B], c Reader[R, C], d Reader[R, D]) Reader[R, T.Tuple4[A, B, C, D]] {
|
||||
return G.SequenceT4[Reader[R, A], Reader[R, B], Reader[R, C], Reader[R, D], Reader[R, T.Tuple4[A, B, C, D]]](a, b, c, d)
|
||||
}
|
Reference in New Issue
Block a user