diff --git a/internal/optiont/option.go b/internal/optiont/option.go index 50977f3..2126b1d 100644 --- a/internal/optiont/option.go +++ b/internal/optiont/option.go @@ -49,6 +49,16 @@ func MonadChain[A, B, HKTFA, HKTFB any]( return fchain(ma, O.Fold(F.Nullary2(O.None[B], fof), f)) } +func Chain[A, B, HKTFA, HKTFB any]( + fchain func(HKTFA, func(O.Option[A]) HKTFB) HKTFB, + fof func(O.Option[B]) HKTFB, + f func(A) HKTFB) func(ma HKTFA) HKTFB { + // dispatch to the even more generic implementation + return func(ma HKTFA) HKTFB { + return MonadChain(fchain, fof, ma, f) + } +} + func MonadAp[A, B, HKTFAB, HKTFGAB, HKTFA, HKTFB any]( fap func(HKTFGAB, HKTFA) HKTFB, fmap func(HKTFAB, func(O.Option[func(A) B]) func(O.Option[A]) O.Option[B]) HKTFGAB, diff --git a/iooption/generic/iooption.go b/iooption/generic/iooption.go index 52b42de..f9e1cc0 100644 --- a/iooption/generic/iooption.go +++ b/iooption/generic/iooption.go @@ -20,6 +20,7 @@ import ( ET "github.com/IBM/fp-go/either" F "github.com/IBM/fp-go/function" + C "github.com/IBM/fp-go/internal/chain" FI "github.com/IBM/fp-go/internal/fromio" "github.com/IBM/fp-go/internal/optiont" IO "github.com/IBM/fp-go/io/generic" @@ -76,8 +77,48 @@ func MonadChain[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](fa GA, return optiont.MonadChain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], fa, f) } +// MonadChainFirst runs the monad returned by the function but returns the result of the original monad +func MonadChainFirst[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](ma GA, f func(A) GB) GA { + return C.MonadChainFirst( + MonadChain[GA, GA, A, A], + MonadMap[GB, GA, B, A], + ma, + f, + ) +} + +// 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], + f, + ) +} + +// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad +func MonadChainFirstIOK[GA ~func() O.Option[A], GIOB ~func() B, A, B any](first GA, f func(A) GIOB) GA { + return FI.MonadChainFirstIOK( + MonadChain[GA, GA, A, A], + MonadMap[func() O.Option[B], GA, B, A], + FromIO[func() O.Option[B], GIOB, B], + first, + f, + ) +} + +// 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], + FromIO[func() O.Option[B], GIOB, B], + f, + ) +} + func Chain[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](f func(A) GB) func(GA) GB { - return F.Bind2nd(MonadChain[GA, GB, A, B], f) + return optiont.Chain(IO.MonadChain[GA, GB, O.Option[A], O.Option[B]], IO.MonadOf[GB, O.Option[B]], f) } func MonadChainOptionK[GA ~func() O.Option[A], GB ~func() O.Option[B], A, B any](ma GA, f func(A) O.Option[B]) GB { diff --git a/iooption/iooption.go b/iooption/iooption.go index a23c90d..689f77c 100644 --- a/iooption/iooption.go +++ b/iooption/iooption.go @@ -18,6 +18,7 @@ package iooption import ( ET "github.com/IBM/fp-go/either" I "github.com/IBM/fp-go/io" + IO "github.com/IBM/fp-go/io" G "github.com/IBM/fp-go/iooption/generic" L "github.com/IBM/fp-go/lazy" O "github.com/IBM/fp-go/option" @@ -143,3 +144,23 @@ func MonadAlt[A any](first IOOption[A], second L.Lazy[IOOption[A]]) IOOption[A] func Alt[A any](second L.Lazy[IOOption[A]]) func(IOOption[A]) IOOption[A] { return G.Alt(second) } + +// MonadChainFirst runs the monad returned by the function but returns the result of the original monad +func MonadChainFirst[A, B any](ma IOOption[A], f func(A) IOOption[B]) IOOption[A] { + return G.MonadChainFirst[IOOption[A], IOOption[B]](ma, f) +} + +// ChainFirst runs the monad returned by the function but returns the result of the original monad +func ChainFirst[A, B any](f func(A) IOOption[B]) func(IOOption[A]) IOOption[A] { + return G.ChainFirst[IOOption[A], IOOption[B]](f) +} + +// MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad +func MonadChainFirstIOK[A, B any](first IOOption[A], f func(A) IO.IO[B]) IOOption[A] { + return G.MonadChainFirstIOK[IOOption[A], IO.IO[B]](first, f) +} + +// ChainFirstIOK runs the monad returned by the function but returns the result of the original monad +func ChainFirstIOK[A, B any](f func(A) IO.IO[B]) func(IOOption[A]) IOOption[A] { + return G.ChainFirstIOK[IOOption[A], IO.IO[B]](f) +}