diff --git a/identity/generic/identity.go b/identity/generic/identity.go index dc6ef57..033017e 100644 --- a/identity/generic/identity.go +++ b/identity/generic/identity.go @@ -50,7 +50,11 @@ func MonadChainFirst[GAB ~func(A) B, A, B any](fa A, f GAB) A { } func ChainFirst[GAB ~func(A) B, A, B any](f GAB) func(A) A { - return C.ChainFirst(MonadChain[func(A) A, A, A], MonadMap[func(B) A, B, A], f) + return C.ChainFirst( + Chain[func(A) A, A, A], + Map[func(B) A, B, A], + f, + ) } func MonadFlap[GAB ~func(A) B, A, B any](fab GAB, a A) B { diff --git a/internal/chain/chain.go b/internal/chain/chain.go index 79ebc40..1f9406f 100644 --- a/internal/chain/chain.go +++ b/internal/chain/chain.go @@ -43,11 +43,11 @@ func MonadChain[A, B, HKTA, HKTB any]( // HKTA=HKT[A] // HKTB=HKT[B] func ChainFirst[A, B, HKTA, HKTB any]( - mchain func(HKTA, func(A) HKTA) HKTA, - mmap func(HKTB, func(B) A) HKTA, + mchain func(func(A) HKTA) func(HKTA) HKTA, + mmap func(func(B) A) func(HKTB) HKTA, f func(A) HKTB) func(HKTA) HKTA { - return F.Bind2nd(mchain, func(a A) HKTA { - return mmap(f(a), F.Constant1[B](a)) + return mchain(func(a A) HKTA { + return mmap(F.Constant1[B](a))(f(a)) }) } diff --git a/internal/fromeither/either.go b/internal/fromeither/either.go index c71f721..7c8eb52 100644 --- a/internal/fromeither/either.go +++ b/internal/fromeither/either.go @@ -85,8 +85,8 @@ func MonadChainFirstEitherK[A, E, B, HKTEA, HKTEB any]( } func ChainFirstEitherK[A, E, B, HKTEA, HKTEB any]( - mchain func(HKTEA, func(A) HKTEA) HKTEA, - mmap func(HKTEB, func(B) A) HKTEA, + mchain func(func(A) HKTEA) func(HKTEA) HKTEA, + mmap func(func(B) A) func(HKTEB) HKTEA, fromEither func(ET.Either[E, B]) HKTEB, f func(A) ET.Either[E, B]) func(HKTEA) HKTEA { return C.ChainFirst(mchain, mmap, F.Flow2(f, fromEither)) diff --git a/internal/fromio/io.go b/internal/fromio/io.go index 2da57fe..7d8531e 100644 --- a/internal/fromio/io.go +++ b/internal/fromio/io.go @@ -30,8 +30,8 @@ func MonadChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B]( } func ChainFirstIOK[A, B, HKTA, HKTB any, GIOB ~func() B]( - mchain func(HKTA, func(A) HKTA) HKTA, - mmap func(HKTB, func(B) A) HKTA, + mchain func(func(A) HKTA) func(HKTA) HKTA, + mmap func(func(B) A) func(HKTB) HKTA, fromio func(GIOB) HKTB, f func(A) GIOB) func(HKTA) HKTA { // chain diff --git a/internal/fromioeither/ioeither.go b/internal/fromioeither/ioeither.go index d00f757..c6e4e69 100644 --- a/internal/fromioeither/ioeither.go +++ b/internal/fromioeither/ioeither.go @@ -31,8 +31,8 @@ func MonadChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB } func ChainFirstIOEitherK[GIOB ~func() ET.Either[E, B], E, A, B, HKTA, HKTB any]( - mchain func(HKTA, func(A) HKTA) HKTA, - mmap func(HKTB, func(B) A) HKTA, + mchain func(func(A) HKTA) func(HKTA) HKTA, + mmap func(func(B) A) func(HKTB) HKTA, fromio func(GIOB) HKTB, f func(A) GIOB) func(HKTA) HKTA { // chain diff --git a/io/generic/io.go b/io/generic/io.go index fdc9260..1e0bef6 100644 --- a/io/generic/io.go +++ b/io/generic/io.go @@ -100,7 +100,11 @@ func MonadChainFirst[GA ~func() A, GB ~func() B, A, B any](fa GA, f func(A) GB) // ChainFirst composes computations in sequence, using the return value of one computation to determine the next computation and // keeping only the result of the first. func ChainFirst[GA ~func() A, GB ~func() B, A, B any](f func(A) GB) func(GA) GA { - return C.ChainFirst(MonadChain[GA, GA, A, A], MonadMap[GB, GA, B, A], f) + return C.ChainFirst( + Chain[GA, GA, A, A], + Map[GB, GA, B, A], + f, + ) } func ApSeq[GB ~func() B, GAB ~func() func(A) B, GA ~func() A, B, A any](ma GA) func(GAB) GB { diff --git a/ioeither/generic/ioeither.go b/ioeither/generic/ioeither.go index 2aabead..a612b5a 100644 --- a/ioeither/generic/ioeither.go +++ b/ioeither/generic/ioeither.go @@ -257,8 +257,8 @@ func MonadChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, // ChainFirst runs the monad returned by the function but returns the result of the original monad func ChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GA { return C.ChainFirst( - MonadChain[GA, GA, E, A, A], - MonadMap[GB, GA, E, B, A], + Chain[GA, GA, E, A, A], + Map[GB, GA, E, B, A], f, ) } @@ -277,8 +277,8 @@ func MonadChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any] // ChainFirstIOK runs the monad returned by the function but returns the result of the original monad func ChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GA) GA { return FI.ChainFirstIOK( - MonadChain[GA, GA, E, A, A], - MonadMap[func() ET.Either[E, B], GA, E, B, A], + Chain[GA, GA, E, A, A], + Map[func() ET.Either[E, B], GA, E, B, A], FromIO[func() ET.Either[E, B], GIOB, E, B], f, ) @@ -298,8 +298,8 @@ func MonadChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](first GA, f // ChainFirstEitherK runs the monad returned by the function but returns the result of the original monad func ChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GA { return FE.ChainFirstEitherK( - MonadChain[GA, GA, E, A, A], - MonadMap[func() ET.Either[E, B], GA, E, B, A], + Chain[GA, GA, E, A, A], + Map[func() ET.Either[E, B], GA, E, B, A], FromEither[func() ET.Either[E, B], E, B], f, ) diff --git a/iooption/generic/iooption.go b/iooption/generic/iooption.go index e24f1dc..9f51504 100644 --- a/iooption/generic/iooption.go +++ b/iooption/generic/iooption.go @@ -90,8 +90,8 @@ func MonadChainFirst[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](m // ChainFirst runs the monad returned by the function but returns the result of the original monad func ChainFirst[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](f func(A) GB) func(GA) GA { return C.ChainFirst( - MonadChain[GA, GA, A, A], - MonadMap[GB, GA, B, A], + Chain[GA, GA, A, A], + Map[GB, GA, B, A], f, ) } @@ -110,8 +110,8 @@ func MonadChainFirstIOK[GA ~func() O.Option[A], GIOB ~func() B, A, B any](first // ChainFirstIOK runs the monad returned by the function but returns the result of the original monad func ChainFirstIOK[GA ~func() O.Option[A], GIOB ~func() B, A, B any](f func(A) GIOB) func(GA) GA { return FI.ChainFirstIOK( - MonadChain[GA, GA, A, A], - MonadMap[func() O.Option[B], GA, B, A], + Chain[GA, GA, A, A], + Map[func() O.Option[B], GA, B, A], FromIO[func() O.Option[B], GIOB, B], f, ) diff --git a/readerio/generic/reader.go b/readerio/generic/reader.go index a9575b4..c689928 100644 --- a/readerio/generic/reader.go +++ b/readerio/generic/reader.go @@ -114,8 +114,8 @@ func MonadChainFirstIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GI func ChainFirstIOK[GEA ~func(E) GIOA, GEB ~func(E) GIOB, GIOA ~func() A, GIOB ~func() B, E, A, B any](f func(A) GIOB) func(GEA) GEA { return FIO.ChainFirstIOK( - MonadChain[GEA, GEA], - MonadMap[GEB, GEA], + Chain[GEA, GEA], + Map[GEB, GEA], FromIO[GEB], f, ) diff --git a/writer/bind.go b/writer/bind.go index 10b891d..981576b 100644 --- a/writer/bind.go +++ b/writer/bind.go @@ -17,7 +17,6 @@ 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" ) @@ -27,11 +26,11 @@ func Do[S, W any](m M.Monoid[W]) func(S) Writer[W, S] { } // 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( +func Bind[S1, S2, T, W any]( 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) + return G.Bind[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, f) } // Let attaches the result of a computation to a context [S1] to produce a context [S2] @@ -58,9 +57,9 @@ func BindTo[W, S1, T any]( } // 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( +func ApS[S1, S2, T, W any]( 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) + return G.ApS[Writer[W, S1], Writer[W, S2], Writer[W, T], W, S1, S2, T](setter, fa) } diff --git a/writer/bind_test.go b/writer/bind_test.go index 1ad051e..857bc93 100644 --- a/writer/bind_test.go +++ b/writer/bind_test.go @@ -42,8 +42,8 @@ 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), + Bind(utils.SetLastName, getLastName), + Bind(utils.SetGivenName, getGivenName), Map[[]string](utils.GetFullName), ) @@ -54,8 +54,8 @@ 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")), + ApS(utils.SetLastName, Of[string](monoid)("Doe")), + ApS(utils.SetGivenName, Of[string](monoid)("John")), Map[[]string](utils.GetFullName), ) diff --git a/writer/generic/bind.go b/writer/generic/bind.go index 301c4d3..5b90101 100644 --- a/writer/generic/bind.go +++ b/writer/generic/bind.go @@ -20,36 +20,30 @@ import ( 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" + SG "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 { +func Do[GS ~func() T.Tuple3[S, W, SG.Semigroup[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( +func Bind[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any]( 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, - ) - } + return C.Bind( + Chain[GS2, GS1, func(S1) GS2, W, S1, S2], + 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]( +func Let[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, A any]( key func(A) func(S1) S2, f func(S1) A, ) func(GS1) GS2 { @@ -61,7 +55,7 @@ func Let[GS1 ~func() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], W, S1, S2, A } // 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]( +func LetTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], W, S1, S2, B any]( key func(B) func(S1) S2, b B, ) func(GS1) GS2 { @@ -73,7 +67,7 @@ func LetTo[GS1 ~func() T.Tuple2[S1, W], GS2 ~func() T.Tuple2[S2, W], W, S1, S2, } // 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]( +func BindTo[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, A any]( setter func(A) S1, ) func(GT) GS1 { return C.BindTo( @@ -83,20 +77,14 @@ func BindTo[GS1 ~func() T.Tuple2[S1, W], GT ~func() T.Tuple2[A, W], W, S1, A any } // 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( +func ApS[GS1 ~func() T.Tuple3[S1, W, SG.Semigroup[W]], GS2 ~func() T.Tuple3[S2, W, SG.Semigroup[W]], GT ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, S1, S2, A any]( 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, - ) - } + return apply.ApS( + Ap[GS2, func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GT, W, A, S2], + Map[func() T.Tuple3[func(A) S2, W, SG.Semigroup[W]], GS1, func(S1) func(A) S2], + setter, + fa, + ) } diff --git a/writer/generic/eq.go b/writer/generic/eq.go index 4eacb21..9bd9092 100644 --- a/writer/generic/eq.go +++ b/writer/generic/eq.go @@ -17,11 +17,12 @@ package generic import ( EQ "github.com/IBM/fp-go/eq" + SG "github.com/IBM/fp-go/semigroup" T "github.com/IBM/fp-go/tuple" ) // Constructs an equal predicate for a [Writer] -func Eq[GA ~func() T.Tuple2[A, W], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] { +func Eq[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](w EQ.Eq[W], a EQ.Eq[A]) EQ.Eq[GA] { return EQ.FromEquals(func(l, r GA) bool { ll := l() rr := r() @@ -31,6 +32,6 @@ 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.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.Tuple3[A, W, SG.Semigroup[W]], W, A comparable]() EQ.Eq[GA] { return Eq[GA](EQ.FromStrictEquals[W](), EQ.FromStrictEquals[A]()) } diff --git a/writer/generic/writer.go b/writer/generic/writer.go index a1b6ce9..1acc9d9 100644 --- a/writer/generic/writer.go +++ b/writer/generic/writer.go @@ -17,121 +17,118 @@ package generic import ( F "github.com/IBM/fp-go/function" + C "github.com/IBM/fp-go/internal/chain" IO "github.com/IBM/fp-go/io/generic" M "github.com/IBM/fp-go/monoid" - S "github.com/IBM/fp-go/semigroup" + SG "github.com/IBM/fp-go/semigroup" T "github.com/IBM/fp-go/tuple" ) -func Of[GA ~func() T.Tuple2[A, W], W, A any](m M.Monoid[W]) func(A) GA { +func Of[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](m M.Monoid[W]) func(A) GA { return F.Flow2( - F.Bind2nd(T.MakeTuple2[A, W], m.Empty()), + F.Bind23of3(T.MakeTuple3[A, W, SG.Semigroup[W]])(m.Empty(), M.ToSemigroup(m)), IO.Of[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] { +func Listen[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GTA ~func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]], W, A any](fa GA) GTA { + return func() T.Tuple3[T.Tuple2[A, W], W, SG.Semigroup[W]] { t := fa() - return T.MakeTuple2(T.MakeTuple2(t.F1, t.F2), t.F2) + return T.MakeTuple3(T.MakeTuple2(t.F1, t.F2), t.F2, t.F3) } } // 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] { +func Pass[GFA ~func() T.Tuple3[T.Tuple2[A, FCT], W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GFA) GA { + return func() T.Tuple3[A, W, SG.Semigroup[W]] { t := fa() - return T.MakeTuple2(t.F1.F1, t.F1.F2(t.F2)) + return T.MakeTuple3(t.F1.F1, t.F1.F2(t.F2), t.F3) } } -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])) +func MonadMap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](fa GA, f FCT) GB { + return IO.MonadMap[GA, GB](fa, T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]])) } -func Map[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB { - return IO.Map[GA, GB](T.Map2(f, F.Identity[W])) +func Map[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) B, W, A, B any](f FCT) func(GA) GB { + return IO.Map[GA, GB](T.Map3(f, F.Identity[W], F.Identity[SG.Semigroup[W]])) } -func MonadChain[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) GB, W, A, B any](s S.Semigroup[W]) func(GA, FCT) GB { - return func(fa GA, f FCT) GB { +func MonadChain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](fa GA, f FCT) GB { + return func() T.Tuple3[B, W, SG.Semigroup[W]] { + a := fa() + b := f(a.F1)() - return func() T.Tuple2[B, W] { - a := fa() - b := f(a.F1)() - - return T.MakeTuple2(b.F1, s.Concat(a.F2, b.F2)) - } + return T.MakeTuple3(b.F1, b.F3.Concat(a.F2, b.F2), b.F3) } } -func Chain[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) GB, W, A, B any](s S.Semigroup[W]) func(FCT) func(GA) GB { - return F.Curry2(F.Swap(MonadChain[GB, GA, FCT](s))) +func Chain[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GB { + return F.Bind2nd(MonadChain[GB, GA, FCT, W, A, B], f) } -func MonadAp[GB ~func() T.Tuple2[B, W], GAB ~func() T.Tuple2[func(A) B, W], GA ~func() T.Tuple2[A, W], W, A, B any](s S.Semigroup[W]) func(GAB, GA) GB { - return func(fab GAB, fa GA) GB { - return func() T.Tuple2[B, W] { - f := fab() - a := fa() +func MonadAp[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](fab GAB, fa GA) GB { + return func() T.Tuple3[B, W, SG.Semigroup[W]] { + f := fab() + a := fa() - return T.MakeTuple2(f.F1(a.F1), s.Concat(f.F2, a.F2)) - } + return T.MakeTuple3(f.F1(a.F1), f.F3.Concat(f.F2, a.F2), f.F3) } } -func Ap[GB ~func() T.Tuple2[B, W], GAB ~func() T.Tuple2[func(A) B, W], GA ~func() T.Tuple2[A, W], W, A, B any](s S.Semigroup[W]) func(GA) func(GAB) GB { - return F.Curry2(F.Swap(MonadAp[GB, GAB, GA](s))) +func Ap[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[func(A) B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A, B any](ga GA) func(GAB) GB { + return F.Bind2nd(MonadAp[GB, GAB, GA], ga) } -func MonadChainFirst[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) GB, W, A, B any](s S.Semigroup[W]) func(GA, FCT) GA { - chain := MonadChain[GA, GA, func(A) GA](s) - return func(ma GA, f FCT) GA { - return chain(ma, func(a A) GA { - return MonadMap[GA](f(a), F.Constant1[B](a)) - }) - } +func MonadChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](ma GA, f FCT) GA { + return C.MonadChainFirst( + MonadChain[GA, GA, func(A) GA], + MonadMap[GA, GB, func(B) A], + ma, + f, + ) } -func ChainFirst[GB ~func() T.Tuple2[B, W], GA ~func() T.Tuple2[A, W], FCT ~func(A) GB, W, A, B any](s S.Semigroup[W]) func(FCT) func(GA) GA { - return F.Curry2(F.Swap(MonadChainFirst[GB, GA, FCT](s))) +func ChainFirst[GB ~func() T.Tuple3[B, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(A) GB, W, A, B any](f FCT) func(GA) GA { + return C.ChainFirst( + Chain[GA, GA, func(A) GA], + Map[GA, GB, func(B) A], + f, + ) } -func Flatten[GAA ~func() T.Tuple2[GA, W], GA ~func() T.Tuple2[A, W], W, A any](s S.Semigroup[W]) func(GAA) GA { - chain := MonadChain[GA, GAA, func(GA) GA](s) - return func(mma GAA) GA { - return chain(mma, F.Identity[GA]) - } +func Flatten[GAA ~func() T.Tuple3[GA, W, SG.Semigroup[W]], GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](mma GAA) GA { + return MonadChain[GA, GAA, func(GA) GA](mma, F.Identity[GA]) } -func Execute[GA ~func() T.Tuple2[A, W], W, A any](fa GA) W { - return T.Second(fa()) +func Execute[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) W { + return fa().F2 } -func Evaluate[GA ~func() T.Tuple2[A, W], W, A any](fa GA) A { - return T.First(fa()) +func Evaluate[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], W, A any](fa GA) A { + return fa().F1 } // MonadCensor modifies the final accumulator value by applying a function -func MonadCensor[GA ~func() T.Tuple2[A, W], FCT ~func(W) W, W, A any](fa GA, f FCT) GA { - return IO.MonadMap[GA, GA](fa, T.Map2(F.Identity[A], f)) +func MonadCensor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](fa GA, f FCT) GA { + return IO.MonadMap[GA, GA](fa, T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]])) } // Censor modifies the final accumulator value by applying a function -func Censor[GA ~func() T.Tuple2[A, W], FCT ~func(W) W, W, A any](f FCT) func(GA) GA { - return IO.Map[GA, GA](T.Map2(F.Identity[A], f)) +func Censor[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], FCT ~func(W) W, W, A any](f FCT) func(GA) GA { + return IO.Map[GA, GA](T.Map3(F.Identity[A], f, F.Identity[SG.Semigroup[W]])) } // MonadListens projects a value from modifications made to the accumulator during an action -func MonadListens[GA ~func() T.Tuple2[A, W], GAB ~func() T.Tuple2[T.Tuple2[A, B], W], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB { - return func() T.Tuple2[T.Tuple2[A, B], W] { +func MonadListens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](fa GA, f FCT) GAB { + return func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]] { a := fa() - return T.MakeTuple2(T.MakeTuple2(a.F1, f(a.F2)), a.F2) + return T.MakeTuple3(T.MakeTuple2(a.F1, f(a.F2)), a.F2, a.F3) } } // Listens projects a value from modifications made to the accumulator during an action -func Listens[GA ~func() T.Tuple2[A, W], GAB ~func() T.Tuple2[T.Tuple2[A, B], W], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB { +func Listens[GA ~func() T.Tuple3[A, W, SG.Semigroup[W]], GAB ~func() T.Tuple3[T.Tuple2[A, B], W, SG.Semigroup[W]], FCT ~func(W) B, W, A, B any](f FCT) func(GA) GAB { return F.Bind2nd(MonadListens[GA, GAB, FCT], f) } diff --git a/writer/testing/laws.go b/writer/testing/laws.go index 107bf70..ed24c06 100644 --- a/writer/testing/laws.go +++ b/writer/testing/laws.go @@ -37,8 +37,6 @@ func AssertLaws[W, A, B, C any](t *testing.T, bc func(B) C, ) func(a A) bool { - s := M.ToSemigroup(m) - return L.AssertLaws(t, WRT.Eq(eqw, eqa), WRT.Eq(eqw, eqb), @@ -60,18 +58,18 @@ func AssertLaws[W, A, B, C any](t *testing.T, WRT.MonadMap[func(func(B) C) func(func(A) B) func(A) C, W, func(B) C, func(func(A) B) func(A) C], - WRT.MonadChain[func(A) WRT.Writer[W, A], W, A, A](m), - WRT.MonadChain[func(A) WRT.Writer[W, B], W, A, B](m), - WRT.MonadChain[func(A) WRT.Writer[W, C], W, A, C](m), - WRT.MonadChain[func(B) WRT.Writer[W, C], W, B, C](m), + WRT.MonadChain[func(A) WRT.Writer[W, A], W, A, A], + WRT.MonadChain[func(A) WRT.Writer[W, B], W, A, B], + WRT.MonadChain[func(A) WRT.Writer[W, C], W, A, C], + WRT.MonadChain[func(B) WRT.Writer[W, C], W, B, C], - WRT.MonadAp[A, A](s), - WRT.MonadAp[B, A](s), - WRT.MonadAp[C, B](s), - WRT.MonadAp[C, A](s), + WRT.MonadAp[A, A, W], + WRT.MonadAp[B, A, W], + WRT.MonadAp[C, B, W], + WRT.MonadAp[C, A, W], - WRT.MonadAp[B, func(A) B](s), - WRT.MonadAp[func(A) C, func(A) B](s), + WRT.MonadAp[B, func(A) B, W], + WRT.MonadAp[func(A) C, func(A) B, W], ab, bc, diff --git a/writer/writer.go b/writer/writer.go index f0bef00..6b7fff9 100644 --- a/writer/writer.go +++ b/writer/writer.go @@ -24,7 +24,7 @@ import ( G "github.com/IBM/fp-go/writer/generic" ) -type Writer[W, A any] IO.IO[T.Tuple2[A, W]] +type Writer[W, A any] IO.IO[T.Tuple3[A, W, S.Semigroup[W]]] func Of[A, W any](m M.Monoid[W]) func(A) Writer[W, A] { return G.Of[Writer[W, A]](m) @@ -48,32 +48,32 @@ 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) } -func MonadChain[FCT ~func(A) Writer[W, B], W, A, B any](s S.Semigroup[W]) func(Writer[W, A], FCT) Writer[W, B] { - return G.MonadChain[Writer[W, B], Writer[W, A], FCT](s) +func MonadChain[FCT ~func(A) Writer[W, B], W, A, B any](fa Writer[W, A], fct FCT) Writer[W, B] { + return G.MonadChain[Writer[W, B], Writer[W, A], FCT](fa, fct) } -func Chain[A, B, W any](s S.Semigroup[W]) func(func(A) Writer[W, B]) func(Writer[W, A]) Writer[W, B] { - return G.Chain[Writer[W, B], Writer[W, A], func(A) Writer[W, B]](s) +func Chain[A, B, W any](fa func(A) Writer[W, B]) func(Writer[W, A]) Writer[W, B] { + return G.Chain[Writer[W, B], Writer[W, A], func(A) Writer[W, B]](fa) } -func MonadAp[B, A, W any](s S.Semigroup[W]) func(Writer[W, func(A) B], Writer[W, A]) Writer[W, B] { - return G.MonadAp[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](s) +func MonadAp[B, A, W any](fab Writer[W, func(A) B], fa Writer[W, A]) Writer[W, B] { + return G.MonadAp[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](fab, fa) } -func Ap[B, A, W any](s S.Semigroup[W]) func(Writer[W, A]) func(Writer[W, func(A) B]) Writer[W, B] { - return G.Ap[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](s) +func Ap[B, A, W any](fa Writer[W, A]) func(Writer[W, func(A) B]) Writer[W, B] { + return G.Ap[Writer[W, B], Writer[W, func(A) B], Writer[W, A]](fa) } -func MonadChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](s S.Semigroup[W]) func(Writer[W, A], FCT) Writer[W, A] { - return G.MonadChainFirst[Writer[W, B], Writer[W, A], FCT](s) +func MonadChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](fa Writer[W, A], fct FCT) Writer[W, A] { + return G.MonadChainFirst[Writer[W, B], Writer[W, A], FCT](fa, fct) } -func ChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](s S.Semigroup[W]) func(FCT) func(Writer[W, A]) Writer[W, A] { - return G.ChainFirst[Writer[W, B], Writer[W, A], FCT](s) +func ChainFirst[FCT ~func(A) Writer[W, B], W, A, B any](fct FCT) func(Writer[W, A]) Writer[W, A] { + return G.ChainFirst[Writer[W, B], Writer[W, A], FCT](fct) } -func Flatten[W, A any](s S.Semigroup[W]) func(Writer[W, Writer[W, A]]) Writer[W, A] { - return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](s) +func Flatten[W, A any](mma Writer[W, Writer[W, A]]) Writer[W, A] { + return G.Flatten[Writer[W, Writer[W, A]], Writer[W, A]](mma) } // Execute extracts the accumulator diff --git a/writer/writer_test.go b/writer/writer_test.go index 97d2448..c584ddc 100644 --- a/writer/writer_test.go +++ b/writer/writer_test.go @@ -20,30 +20,28 @@ import ( A "github.com/IBM/fp-go/array" F "github.com/IBM/fp-go/function" - M "github.com/IBM/fp-go/monoid" + S "github.com/IBM/fp-go/semigroup" T "github.com/IBM/fp-go/tuple" ) func doubleAndLog(data int) Writer[[]string, int] { - return func() T.Tuple2[int, []string] { + return func() T.Tuple3[int, []string, S.Semigroup[[]string]] { result := data * 2 - return T.MakeTuple2(result, A.Of(fmt.Sprintf("Doubled %d -> %d", data, result))) + return T.MakeTuple3(result, A.Of(fmt.Sprintf("Doubled %d -> %d", data, result)), sg) } } func ExampleWriter_logging() { - m := A.Monoid[string]() - s := M.ToSemigroup(m) - - res := F.Pipe3( + res := F.Pipe4( 10, - Of[int](m), - Chain[int, int](s)(doubleAndLog), - Chain[int, int](s)(doubleAndLog), + Of[int](monoid), + Chain(doubleAndLog), + Chain(doubleAndLog), + Execute[[]string, int], ) - fmt.Println(res()) + fmt.Println(res) - // Output: Tuple2[int, []string](40, [Doubled 10 -> 20 Doubled 20 -> 40]) + // Output: [Doubled 10 -> 20 Doubled 20 -> 40] }