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:
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,
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user