// Copyright (c) 2023 IBM Corp. // All rights reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package generic import ( "time" ET "github.com/IBM/fp-go/either" F "github.com/IBM/fp-go/function" C "github.com/IBM/fp-go/internal/chain" "github.com/IBM/fp-go/internal/eithert" FE "github.com/IBM/fp-go/internal/fromeither" FI "github.com/IBM/fp-go/internal/fromio" FC "github.com/IBM/fp-go/internal/functor" IO "github.com/IBM/fp-go/io/generic" O "github.com/IBM/fp-go/option" ) // type IOEither[E, A any] = func() Either[E, A] func MakeIO[GA ~func() ET.Either[E, A], E, A any](f GA) GA { return f } func Left[GA ~func() ET.Either[E, A], E, A any](l E) GA { return MakeIO(eithert.Left(IO.MonadOf[GA, ET.Either[E, A]], l)) } func Right[GA ~func() ET.Either[E, A], E, A any](r A) GA { return MakeIO(eithert.Right(IO.MonadOf[GA, ET.Either[E, A]], r)) } func Of[GA ~func() ET.Either[E, A], E, A any](r A) GA { return Right[GA](r) } func MonadOf[GA ~func() ET.Either[E, A], E, A any](r A) GA { return Of[GA](r) } func LeftIO[GA ~func() ET.Either[E, A], GE ~func() E, E, A any](ml GE) GA { return MakeIO(eithert.LeftF(IO.MonadMap[GE, GA, E, ET.Either[E, A]], ml)) } func RightIO[GA ~func() ET.Either[E, A], GR ~func() A, E, A any](mr GR) GA { return MakeIO(eithert.RightF(IO.MonadMap[GR, GA, A, ET.Either[E, A]], mr)) } func FromEither[GA ~func() ET.Either[E, A], E, A any](e ET.Either[E, A]) GA { return IO.Of[GA](e) } func FromOption[GA ~func() ET.Either[E, A], E, A any](onNone func() E) func(o O.Option[A]) GA { return FE.FromOption( FromEither[GA, E, A], onNone, ) } func ChainOptionK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](onNone func() E) func(func(A) O.Option[B]) func(GA) GB { return FE.ChainOptionK( MonadChain[GA, GB, E, A, B], FromEither[GB, E, B], onNone, ) } func FromIO[GA ~func() ET.Either[E, A], GR ~func() A, E, A any](mr GR) GA { return RightIO[GA](mr) } func MonadMap[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) B) GB { return eithert.MonadMap(IO.MonadMap[GA, GB, ET.Either[E, A], ET.Either[E, B]], fa, f) } func Map[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) B) func(GA) GB { return F.Bind2nd(MonadMap[GA, GB, E, A, B], f) } func MonadMapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, b B) GB { return MonadMap[GA, GB](fa, F.Constant1[A](b)) } func MapTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](b B) func(GA) GB { return F.Bind2nd(MonadMapTo[GA, GB, E, A, B], b) } func MonadChain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, f func(A) GB) GB { return eithert.MonadChain(IO.MonadChain[GA, GB, ET.Either[E, A], ET.Either[E, B]], IO.MonadOf[GB, ET.Either[E, B]], fa, f) } func Chain[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) GB) func(GA) GB { return F.Bind2nd(MonadChain[GA, GB, E, A, B], f) } func MonadChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fa GA, fb GB) GB { return MonadChain(fa, F.Constant1[A](fb)) } func ChainTo[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](fb GB) func(GA) GB { return F.Bind2nd(MonadChainTo[GA, GB, E, A, B], fb) } func MonadChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) ET.Either[E, B]) GB { return FE.MonadChainEitherK( MonadChain[GA, GB, E, A, B], FromEither[GB, E, B], ma, f, ) } func MonadChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](ma GA, f func(A) GR) GB { return FI.MonadChainIOK( MonadChain[GA, GB, E, A, B], FromIO[GB, GR, E, B], ma, f, ) } func ChainIOK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], GR ~func() B, E, A, B any](f func(A) GR) func(GA) GB { return FI.ChainIOK( MonadChain[GA, GB, E, A, B], FromIO[GB, GR, E, B], f, ) } func ChainEitherK[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](f func(A) ET.Either[E, B]) func(GA) GB { return F.Bind2nd(MonadChainEitherK[GA, GB, E, A, B], f) } func MonadAp[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB { return eithert.MonadAp( IO.MonadAp[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]], IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]], mab, ma) } func Ap[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB { return F.Bind2nd(MonadAp[GB, GAB, GA], ma) } func MonadApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB { return eithert.MonadAp( IO.MonadApSeq[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]], IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]], mab, ma) } func ApSeq[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB { return F.Bind2nd(MonadApSeq[GB, GAB, GA], ma) } func MonadApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](mab GAB, ma GA) GB { return eithert.MonadAp( IO.MonadApPar[GA, GB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, A], ET.Either[E, B]], IO.MonadMap[GAB, func() func(ET.Either[E, A]) ET.Either[E, B], ET.Either[E, func(A) B], func(ET.Either[E, A]) ET.Either[E, B]], mab, ma) } func ApPar[GB ~func() ET.Either[E, B], GAB ~func() ET.Either[E, func(A) B], GA ~func() ET.Either[E, A], E, A, B any](ma GA) func(GAB) GB { return F.Bind2nd(MonadApPar[GB, GAB, GA], ma) } func Flatten[GA ~func() ET.Either[E, A], GAA ~func() ET.Either[E, GA], E, A any](mma GAA) GA { return MonadChain(mma, F.Identity[GA]) } func TryCatch[GA ~func() ET.Either[E, A], E, A any](f func() (A, error), onThrow func(error) E) GA { return MakeIO(func() ET.Either[E, A] { a, err := f() return ET.TryCatch(a, err, onThrow) }) } func TryCatchError[GA ~func() ET.Either[error, A], A any](f func() (A, error)) GA { return MakeIO(func() ET.Either[error, A] { return ET.TryCatchError(f()) }) } // Memoize computes the value of the provided IO monad lazily but exactly once func Memoize[GA ~func() ET.Either[E, A], E, A any](ma GA) GA { return IO.Memoize(ma) } func MonadMapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](fa GA1, f func(E1) E2) GA2 { return eithert.MonadMapLeft(IO.MonadMap[GA1, GA2, ET.Either[E1, A], ET.Either[E2, A]], fa, f) } func MapLeft[GA1 ~func() ET.Either[E1, A], GA2 ~func() ET.Either[E2, A], E1, E2, A any](f func(E1) E2) func(GA1) GA2 { return F.Bind2nd(MonadMapLeft[GA1, GA2, E1, E2, A], f) } // Delay creates an operation that passes in the value after some delay func Delay[GA ~func() ET.Either[E, A], E, A any](delay time.Duration) func(GA) GA { return IO.Delay[GA](delay) } func MonadBiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](fa GA, f func(E1) E2, g func(A) B) GB { return eithert.MonadBiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], fa, f, g) } // BiMap maps a pair of functions over the two type arguments of the bifunctor. func BiMap[GA ~func() ET.Either[E1, A], GB ~func() ET.Either[E2, B], E1, E2, A, B any](f func(E1) E2, g func(A) B) func(GA) GB { return eithert.BiMap(IO.MonadMap[GA, GB, ET.Either[E1, A], ET.Either[E2, B]], f, g) } // Fold convers an IOEither into an IO func Fold[GA ~func() ET.Either[E, A], GB ~func() B, E, A, B any](onLeft func(E) GB, onRight func(A) GB) func(GA) GB { return eithert.MatchE(IO.MonadChain[GA, GB, ET.Either[E, A], B], onLeft, onRight) } func MonadFold[GA ~func() ET.Either[E, A], GB ~func() B, E, A, B any](ma GA, onLeft func(E) GB, onRight func(A) GB) GB { return eithert.FoldE(IO.MonadChain[GA, GB, ET.Either[E, A], B], ma, onLeft, onRight) } // GetOrElse extracts the value or maps the error func GetOrElse[GA ~func() ET.Either[E, A], GB ~func() A, E, A any](onLeft func(E) GB) func(GA) GB { return eithert.GetOrElse(IO.MonadChain[GA, GB, ET.Either[E, A], A], IO.MonadOf[GB, A], onLeft) } // MonadChainFirst runs the monad returned by the function but returns the result of the original monad func MonadChainFirst[GA ~func() ET.Either[E, A], GB ~func() ET.Either[E, B], E, A, B any](ma GA, f func(A) GB) GA { return C.MonadChainFirst( MonadChain[GA, GA, E, A, A], MonadMap[GB, GA, E, B, A], ma, f, ) } // 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], f, ) } // MonadChainFirstIOK runs the monad returned by the function but returns the result of the original monad func MonadChainFirstIOK[GA ~func() ET.Either[E, A], GIOB ~func() B, E, A, B any](first GA, f func(A) GIOB) GA { return FI.MonadChainFirstIOK( MonadChain[GA, GA, E, A, A], MonadMap[func() ET.Either[E, B], GA, E, B, A], FromIO[func() ET.Either[E, B], GIOB, E, B], first, f, ) } // 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], FromIO[func() ET.Either[E, B], GIOB, E, B], f, ) } // MonadChainFirstEitherK runs the monad returned by the function but returns the result of the original monad func MonadChainFirstEitherK[GA ~func() ET.Either[E, A], E, A, B any](first GA, f func(A) ET.Either[E, B]) GA { return FE.MonadChainFirstEitherK( MonadChain[GA, GA, E, A, A], MonadMap[func() ET.Either[E, B], GA, E, B, A], FromEither[func() ET.Either[E, B], E, B], first, 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], FromEither[func() ET.Either[E, B], E, B], f, ) } // Swap changes the order of type parameters func Swap[GEA ~func() ET.Either[E, A], GAE ~func() ET.Either[A, E], E, A any](val GEA) GAE { return MonadFold(val, Right[GAE], Left[GAE]) } // FromImpure converts a side effect without a return value into a side effect that returns any func FromImpure[GA ~func() ET.Either[E, any], IMP ~func(), E any](f IMP) GA { return F.Pipe2( f, IO.FromImpure[func() any, IMP], FromIO[GA, func() any], ) } // Defer creates an IO by creating a brand new IO via a generator function, each time func Defer[GEA ~func() ET.Either[E, A], E, A any](gen func() GEA) GEA { return IO.Defer[GEA](gen) } func MonadAlt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](first GIOA, second LAZY) GIOA { return eithert.MonadAlt( IO.Of[GIOA], IO.MonadChain[GIOA, GIOA], first, second, ) } func Alt[LAZY ~func() GIOA, GIOA ~func() ET.Either[E, A], E, A any](second LAZY) func(GIOA) GIOA { return F.Bind2nd(MonadAlt[LAZY], second) } func MonadFlap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](fab GEAB, a A) GEB { return FC.MonadFlap(MonadMap[GEAB, GEB], fab, a) } func Flap[GEAB ~func() ET.Either[E, func(A) B], GEB ~func() ET.Either[E, B], E, B, A any](a A) func(GEAB) GEB { return FC.Flap(MonadMap[GEAB, GEB], a) }