1
0
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:
Dr. Carsten Leue
2023-07-14 23:52:14 +02:00
parent 5020437b6a
commit 84c3e3ff88
101 changed files with 4440 additions and 13 deletions

31
reader/generic/array.go Normal file
View 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
View 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
View 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
View 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)
}

View 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,
)
}