diff --git a/array/nonempty/array.go b/array/nonempty/array.go index b72962f..8f56c0e 100644 --- a/array/nonempty/array.go +++ b/array/nonempty/array.go @@ -19,6 +19,7 @@ import ( G "github.com/IBM/fp-go/array/generic" F "github.com/IBM/fp-go/function" "github.com/IBM/fp-go/internal/array" + S "github.com/IBM/fp-go/semigroup" ) // NonEmptyArray represents an array with at least one element @@ -29,7 +30,7 @@ func Of[A any](first A) NonEmptyArray[A] { return G.Of[NonEmptyArray[A]](first) } -// From constructs an array from a set of variadic arguments +// From constructs a [NonEmptyArray] from a set of variadic arguments func From[A any](first A, data ...A) NonEmptyArray[A] { count := len(data) if count == 0 { @@ -103,3 +104,21 @@ func MonadAp[B, A any](fab NonEmptyArray[func(A) B], fa NonEmptyArray[A]) NonEmp func Ap[B, A any](fa NonEmptyArray[A]) func(NonEmptyArray[func(A) B]) NonEmptyArray[B] { return G.Ap[NonEmptyArray[B], NonEmptyArray[func(A) B]](fa) } + +// FoldMap maps and folds a [NonEmptyArray]. Map the [NonEmptyArray] passing each value to the iterating function. Then fold the results using the provided [Semigroup]. +func FoldMap[A, B any](s S.Semigroup[B]) func(func(A) B) func(NonEmptyArray[A]) B { + return func(f func(A) B) func(NonEmptyArray[A]) B { + return func(as NonEmptyArray[A]) B { + return array.Reduce(Tail(as), func(cur B, a A) B { + return s.Concat(cur, f(a)) + }, f(Head(as))) + } + } +} + +// Fold folds the [NonEmptyArray] using the provided [Semigroup]. +func Fold[A any](s S.Semigroup[A]) func(NonEmptyArray[A]) A { + return func(as NonEmptyArray[A]) A { + return array.Reduce(Tail(as), s.Concat, Head(as)) + } +} diff --git a/context/readerioeither/monoid.go b/context/readerioeither/monoid.go index 4e5e105..834fa19 100644 --- a/context/readerioeither/monoid.go +++ b/context/readerioeither/monoid.go @@ -17,6 +17,7 @@ package readerioeither import ( G "github.com/IBM/fp-go/context/readerioeither/generic" + L "github.com/IBM/fp-go/lazy" M "github.com/IBM/fp-go/monoid" ) @@ -34,3 +35,22 @@ func ApplicativeMonoidSeq[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] { func ApplicativeMonoidPar[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] { return G.ApplicativeMonoidPar[ReaderIOEither[A], ReaderIOEither[func(A) A]](m) } + +// AlternativeMonoid is the alternative [Monoid] for [ReaderIOEither] +func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[ReaderIOEither[A]] { + return M.AlternativeMonoid( + Of[A], + MonadMap[A, func(A) A], + MonadAp[A, A], + MonadAlt[A], + m, + ) +} + +// AltMonoid is the alternative [Monoid] for an [ReaderIOEither] +func AltMonoid[A any](zero L.Lazy[ReaderIOEither[A]]) M.Monoid[ReaderIOEither[A]] { + return M.AltMonoid( + zero, + MonadAlt[A], + ) +} diff --git a/either/either.go b/either/either.go index 2dd5542..d84ede4 100644 --- a/either/either.go +++ b/either/either.go @@ -23,6 +23,7 @@ import ( E "github.com/IBM/fp-go/errors" F "github.com/IBM/fp-go/function" FC "github.com/IBM/fp-go/internal/functor" + L "github.com/IBM/fp-go/lazy" O "github.com/IBM/fp-go/option" ) @@ -198,11 +199,11 @@ func Reduce[E, A, B any](f func(B, A) B, initial B) func(Either[E, A]) B { ) } -func AltW[E, E1, A any](that func() Either[E1, A]) func(Either[E, A]) Either[E1, A] { +func AltW[E, E1, A any](that L.Lazy[Either[E1, A]]) func(Either[E, A]) Either[E1, A] { return Fold(F.Ignore1of1[E](that), Right[E1, A]) } -func Alt[E, A any](that func() Either[E, A]) func(Either[E, A]) Either[E, A] { +func Alt[E, A any](that L.Lazy[Either[E, A]]) func(Either[E, A]) Either[E, A] { return AltW[E](that) } @@ -254,3 +255,7 @@ func MonadFlap[E, A, B any](fab Either[E, func(A) B], a A) Either[E, B] { func Flap[E, A, B any](a A) func(Either[E, func(A) B]) Either[E, B] { return F.Bind2nd(MonadFlap[E, A, B], a) } + +func MonadAlt[E, A any](fa Either[E, A], that L.Lazy[Either[E, A]]) Either[E, A] { + return MonadFold(fa, F.Ignore1of1[E](that), Of[E, A]) +} diff --git a/either/monoid.go b/either/monoid.go new file mode 100644 index 0000000..bd0d593 --- /dev/null +++ b/either/monoid.go @@ -0,0 +1,40 @@ +// 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 either + +import ( + L "github.com/IBM/fp-go/lazy" + M "github.com/IBM/fp-go/monoid" +) + +// AlternativeMonoid is the alternative [Monoid] for an [Either] +func AlternativeMonoid[E, A any](m M.Monoid[A]) M.Monoid[Either[E, A]] { + return M.AlternativeMonoid( + Of[E, A], + MonadMap[E, A, func(A) A], + MonadAp[A, E, A], + MonadAlt[E, A], + m, + ) +} + +// AltMonoid is the alternative [Monoid] for an [Either] +func AltMonoid[E, A any](zero L.Lazy[Either[E, A]]) M.Monoid[Either[E, A]] { + return M.AltMonoid( + zero, + MonadAlt[E, A], + ) +} diff --git a/either/semigroup.go b/either/semigroup.go new file mode 100644 index 0000000..79abbab --- /dev/null +++ b/either/semigroup.go @@ -0,0 +1,27 @@ +// 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 either + +import ( + S "github.com/IBM/fp-go/semigroup" +) + +// AltSemigroup is the alternative [Semigroup] for an [Either] +func AltSemigroup[E, A any]() S.Semigroup[Either[E, A]] { + return S.AltSemigroup( + MonadAlt[E, A], + ) +} diff --git a/monoid/alt.go b/monoid/alt.go index ada82cf..59136c7 100644 --- a/monoid/alt.go +++ b/monoid/alt.go @@ -19,13 +19,13 @@ import ( S "github.com/IBM/fp-go/semigroup" ) -func AlternativeMonoid[A, HKTA, HKTFA any]( +func AlternativeMonoid[A, HKTA, HKTFA any, LAZYHKTA ~func() HKTA]( fof func(A) HKTA, fmap func(HKTA, func(A) func(A) A) HKTFA, fap func(HKTFA, HKTA) HKTA, - falt func(HKTA, func() HKTA) HKTA, + falt func(HKTA, LAZYHKTA) HKTA, m Monoid[A], @@ -45,9 +45,9 @@ func AlternativeMonoid[A, HKTA, HKTFA any]( ) } -func AltMonoid[HKTA any]( - fzero func() HKTA, - falt func(HKTA, func() HKTA) HKTA, +func AltMonoid[HKTA any, LAZYHKTA ~func() HKTA]( + fzero LAZYHKTA, + falt func(HKTA, LAZYHKTA) HKTA, ) Monoid[HKTA] { diff --git a/option/monoid.go b/option/monoid.go index 4eb5519..7c81ae3 100644 --- a/option/monoid.go +++ b/option/monoid.go @@ -51,3 +51,22 @@ func Monoid[A any]() func(S.Semigroup[A]) M.Monoid[Option[A]] { return M.MakeMonoid(sg(s).Concat, None[A]()) } } + +// AlternativeMonoid is the alternative [Monoid] for an [Option] +func AlternativeMonoid[A any](m M.Monoid[A]) M.Monoid[Option[A]] { + return M.AlternativeMonoid( + Of[A], + MonadMap[A, func(A) A], + MonadAp[A, A], + MonadAlt[A], + m, + ) +} + +// AltMonoid is the alternative [Monoid] for an [Option] +func AltMonoid[A any]() M.Monoid[Option[A]] { + return M.AltMonoid( + None[A], + MonadAlt[A], + ) +} diff --git a/option/option.go b/option/option.go index f45ea93..b51a794 100644 --- a/option/option.go +++ b/option/option.go @@ -116,6 +116,10 @@ func Flatten[A any](mma Option[Option[A]]) Option[A] { return MonadChain(mma, F.Identity[Option[A]]) } +func MonadAlt[A any](fa Option[A], that func() Option[A]) Option[A] { + return MonadFold(fa, that, Of[A]) +} + func Alt[A any](that func() Option[A]) func(Option[A]) Option[A] { return Fold(that, Of[A]) } diff --git a/semigroup/alt.go b/semigroup/alt.go index 17b95d9..b527a2d 100644 --- a/semigroup/alt.go +++ b/semigroup/alt.go @@ -15,8 +15,8 @@ package semigroup -func AltSemigroup[HKTA any]( - falt func(HKTA, func() HKTA) HKTA, +func AltSemigroup[HKTA any, LAZYHKTA ~func() HKTA]( + falt func(HKTA, LAZYHKTA) HKTA, ) Semigroup[HKTA] {