1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-07-15 01:24:23 +02:00

fix: slowly migrate IO

Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
Dr. Carsten Leue
2025-03-02 10:57:52 +01:00
parent ddb9e48441
commit eb4218c575
29 changed files with 281 additions and 333 deletions

View File

@ -67,9 +67,9 @@ type MultiInjectionToken[T any] interface {
// makeID creates a generator of unique string IDs
func makeID() IO.IO[string] {
var count atomic.Int64
return IO.MakeIO(func() string {
return func() string {
return strconv.FormatInt(count.Add(1), 16)
})
}
}
// genID is the common generator of unique string IDs

View File

@ -13,19 +13,30 @@
// See the License for the specific language governing permissions and
// limitations under the License.
package generic
package io
import (
"github.com/IBM/fp-go/v2/internal/functor"
"github.com/IBM/fp-go/v2/internal/applicative"
)
type ioFunctor[A, B any, GA ~func() A, GB ~func() B] struct{}
type (
ioApplicative[A, B any] struct{}
IOApplicative[A, B any] = applicative.Applicative[A, B, IO[A], IO[B], IO[func(A) B]]
)
func (o *ioFunctor[A, B, GA, GB]) Map(f func(A) B) func(GA) GB {
return Map[GA, GB, A, B](f)
func (o *ioApplicative[A, B]) Of(a A) IO[A] {
return Of(a)
}
// Functor implements the functoric operations for [IO]
func Functor[A, B any, GA ~func() A, GB ~func() B]() functor.Functor[A, B, GA, GB] {
return &ioFunctor[A, B, GA, GB]{}
func (o *ioApplicative[A, B]) Map(f func(A) B) func(IO[A]) IO[B] {
return Map(f)
}
func (o *ioApplicative[A, B]) Ap(fa IO[A]) func(IO[func(A) B]) IO[B] {
return Ap[B](fa)
}
// Applicative implements the applicativeic operations for [IO]
func Applicative[A, B any]() IOApplicative[A, B] {
return &ioApplicative[A, B]{}
}

View File

@ -16,15 +16,14 @@
package io
import (
G "github.com/IBM/fp-go/v2/io/generic"
M "github.com/IBM/fp-go/v2/monoid"
S "github.com/IBM/fp-go/v2/semigroup"
)
func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[IO[A]] {
return G.ApplySemigroup[IO[A]](s)
return S.ApplySemigroup(MonadMap[A, func(A) A], MonadAp[A, A], s)
}
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[IO[A]] {
return G.ApplicativeMonoid[IO[A]](m)
return M.ApplicativeMonoid(Of[A], MonadMap[A, func(A) A], MonadAp[A, A], m)
}

View File

@ -16,7 +16,7 @@
package io
import (
G "github.com/IBM/fp-go/v2/io/generic"
INTB "github.com/IBM/fp-go/v2/internal/bracket"
)
// Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of
@ -26,5 +26,14 @@ func Bracket[A, B, ANY any](
use func(A) IO[B],
release func(A, B) IO[ANY],
) IO[B] {
return G.Bracket(acquire, use, release)
return INTB.Bracket[IO[A], IO[B], IO[ANY], B, A, B](
Of[B],
MonadChain[A, B],
MonadChain[B, B],
MonadChain[ANY, B],
acquire,
use,
release,
)
}

View File

@ -17,15 +17,24 @@ package io
import (
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/io/generic"
INTE "github.com/IBM/fp-go/v2/internal/eq"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[A any](e EQ.Eq[A]) EQ.Eq[IO[A]] {
return G.Eq[IO[A]](e)
// comparator for the monad
eq := INTE.Eq(
MonadMap[A, func(A) bool],
MonadAp[A, bool],
e,
)
// eagerly execute
return EQ.FromEquals(func(l, r IO[A]) bool {
return eq(l, r)()
})
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[A comparable]() EQ.Eq[IO[A]] {
return G.FromStrictEquals[IO[A]]()
return Eq(EQ.FromStrictEquals[A]())
}

View File

@ -24,16 +24,16 @@ import (
// Close closes a closeable resource and ignores a potential error
func Close[R io.Closer](r R) IO.IO[R] {
return IO.MakeIO[R](func() R {
return func() R {
r.Close() // #nosec: G104
return r
})
}
}
// Remove removes a resource and ignores a potential error
func Remove(name string) IO.IO[string] {
return IO.MakeIO[string](func() string {
return func() string {
os.Remove(name) // #nosec: G104
return name
})
}
}

View File

@ -17,10 +17,19 @@ package io
import (
"github.com/IBM/fp-go/v2/internal/functor"
G "github.com/IBM/fp-go/v2/io/generic"
)
// Functor returns the monadic operations for [IO]
func Functor[A, B any]() functor.Functor[A, B, IO[A], IO[B]] {
return G.Functor[A, B, IO[A], IO[B]]()
type (
ioFunctor[A, B any] struct{}
IOFunctor[A, B any] = functor.Functor[A, B, IO[A], IO[B]]
)
func (o *ioFunctor[A, B]) Map(f func(A) B) func(IO[A]) IO[B] {
return Map(f)
}
// Functor implements the functoric operations for [IO]
func Functor[A, B any]() IOFunctor[A, B] {
return &ioFunctor[A, B]{}
}

View File

@ -1,29 +0,0 @@
// 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 (
M "github.com/IBM/fp-go/v2/monoid"
S "github.com/IBM/fp-go/v2/semigroup"
)
func ApplySemigroup[GA ~func() A, A any](s S.Semigroup[A]) S.Semigroup[GA] {
return S.ApplySemigroup(MonadMap[GA, func() func(A) A, A, func(A) A], MonadAp[GA, GA, func() func(A) A, A, A], s)
}
func ApplicativeMonoid[GA ~func() A, A any](m M.Monoid[A]) M.Monoid[GA] {
return M.ApplicativeMonoid(Of[GA, A], MonadMap[GA, func() func(A) A, A, func(A) A], MonadAp[GA, GA, func() func(A) A, A, A], m)
}

View File

@ -1,40 +0,0 @@
// 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 (
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/internal/eq"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[GA ~func() A, A any](e EQ.Eq[A]) EQ.Eq[GA] {
// comparator for the monad
eq := G.Eq(
MonadMap[GA, func() func(A) bool, A, func(A) bool],
MonadAp[GA, func() bool, func() func(A) bool, A, bool],
e,
)
// eagerly execute
return EQ.FromEquals(func(l, r GA) bool {
return eq(l, r)()
})
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[GA ~func() A, A comparable]() EQ.Eq[GA] {
return Eq[GA](EQ.FromStrictEquals[A]())
}

View File

@ -1,43 +0,0 @@
// Copyright (c) 2024 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 (
"github.com/IBM/fp-go/v2/internal/monad"
)
type ioMonad[A, B any, GA ~func() A, GB ~func() B, GAB ~func() func(A) B] struct{}
func (o *ioMonad[A, B, GA, GB, GAB]) Of(a A) GA {
return Of[GA, A](a)
}
func (o *ioMonad[A, B, GA, GB, GAB]) Map(f func(A) B) func(GA) GB {
return Map[GA, GB, A, B](f)
}
func (o *ioMonad[A, B, GA, GB, GAB]) Chain(f func(A) GB) func(GA) GB {
return Chain[GA, GB, A, B](f)
}
func (o *ioMonad[A, B, GA, GB, GAB]) Ap(fa GA) func(GAB) GB {
return Ap[GB, GAB, GA, B, A](fa)
}
// Monad implements the monadic operations for [Option]
func Monad[A, B any, GA ~func() A, GB ~func() B, GAB ~func() func(A) B]() monad.Monad[A, B, GA, GB, GAB] {
return &ioMonad[A, B, GA, GB, GAB]{}
}

View File

@ -1,31 +0,0 @@
// Copyright (c) 2024 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 (
"github.com/IBM/fp-go/v2/internal/pointed"
)
type ioPointed[A any, GA ~func() A] struct{}
func (o *ioPointed[A, GA]) Of(a A) GA {
return Of[GA, A](a)
}
// Pointed implements the pointedic operations for [IO]
func Pointed[A any, GA ~func() A]() pointed.Pointed[A, GA] {
return &ioPointed[A, GA]{}
}

View File

@ -18,152 +18,253 @@ package io
import (
"time"
G "github.com/IBM/fp-go/v2/io/generic"
F "github.com/IBM/fp-go/v2/function"
INTA "github.com/IBM/fp-go/v2/internal/apply"
INTC "github.com/IBM/fp-go/v2/internal/chain"
INTF "github.com/IBM/fp-go/v2/internal/functor"
INTL "github.com/IBM/fp-go/v2/internal/lazy"
T "github.com/IBM/fp-go/v2/tuple"
)
const (
// useParallel is the feature flag to control if we use the parallel or the sequential implementation of ap
useParallel = true
)
var (
// undefined represents an undefined value
undefined = struct{}{}
)
// IO represents a synchronous computation that cannot fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioltagt] for more details
type IO[A any] func() A
func MakeIO[A any](f func() A) IO[A] {
return G.MakeIO[IO[A]](f)
}
type IO[A any] = func() A
func Of[A any](a A) IO[A] {
return G.Of[IO[A]](a)
return F.Constant(a)
}
func FromIO[A any](a IO[A]) IO[A] {
return G.FromIO(a)
return a
}
// FromImpure converts a side effect without a return value into a side effect that returns any
func FromImpure(f func()) IO[any] {
return G.FromImpure[IO[any]](f)
return func() any {
f()
return undefined
}
}
func MonadOf[A any](a A) IO[A] {
return G.MonadOf[IO[A]](a)
return F.Constant(a)
}
func MonadMap[A, B any](fa IO[A], f func(A) B) IO[B] {
return G.MonadMap[IO[A], IO[B]](fa, f)
return func() B {
return f(fa())
}
}
func Map[A, B any](f func(A) B) func(fa IO[A]) IO[B] {
return G.Map[IO[A], IO[B]](f)
return F.Bind2nd(MonadMap[A, B], f)
}
func MonadMapTo[A, B any](fa IO[A], b B) IO[B] {
return G.MonadMapTo[IO[A], IO[B]](fa, b)
return MonadMap(fa, F.Constant1[A](b))
}
func MapTo[A, B any](b B) func(IO[A]) IO[B] {
return G.MapTo[IO[A], IO[B]](b)
return Map(F.Constant1[A](b))
}
// MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
func MonadChain[A, B any](fa IO[A], f func(A) IO[B]) IO[B] {
return G.MonadChain(fa, f)
return func() B {
return f(fa())()
}
}
// Chain composes computations in sequence, using the return value of one computation to determine the next computation.
func Chain[A, B any](f func(A) IO[B]) func(IO[A]) IO[B] {
return G.Chain[IO[A]](f)
return F.Bind2nd(MonadChain[A, B], f)
}
func MonadAp[B, A any](mab IO[func(A) B], ma IO[A]) IO[B] {
return G.MonadAp[IO[A], IO[B]](mab, ma)
// MonadApSeq implements the applicative on a single thread by first executing mab and the ma
func MonadApSeq[A, B any](mab IO[func(A) B], ma IO[A]) IO[B] {
return MonadChain(mab, F.Bind1st(MonadMap[A, B], ma))
}
// MonadApPar implements the applicative on two threads, the main thread executes mab and the actuall
// apply operation and the second thread computes ma. Communication between the threads happens via a channel
func MonadApPar[A, B any](mab IO[func(A) B], ma IO[A]) IO[B] {
return func() B {
c := make(chan A)
go func() {
c <- ma()
close(c)
}()
return mab()(<-c)
}
}
// MonadAp implements the `ap` operation. Depending on a feature flag this will be sequential or parallel, the preferred implementation
// is parallel
func MonadAp[A, B any](mab IO[func(A) B], ma IO[A]) IO[B] {
if useParallel {
return MonadApPar(mab, ma)
}
return MonadApSeq(mab, ma)
}
func Ap[B, A any](ma IO[A]) func(IO[func(A) B]) IO[B] {
return G.Ap[IO[B], IO[func(A) B], IO[A]](ma)
return F.Bind2nd(MonadAp[A, B], ma)
}
func Flatten[A any](mma IO[IO[A]]) IO[A] {
return G.Flatten(mma)
return MonadChain(mma, F.Identity)
}
// Memoize computes the value of the provided [IO] monad lazily but exactly once
func Memoize[A any](ma IO[A]) IO[A] {
return G.Memoize(ma)
return INTL.Memoize(ma)
}
// MonadChainFirst 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 MonadChainFirst[A, B any](fa IO[A], f func(A) IO[B]) IO[A] {
return G.MonadChainFirst(fa, f)
return INTC.MonadChainFirst(MonadChain[A, A], MonadMap[B, A], fa, f)
}
// 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[A, B any](f func(A) IO[B]) func(IO[A]) IO[A] {
return G.ChainFirst[IO[A]](f)
return INTC.ChainFirst(
Chain[A, A],
Map[B, A],
f,
)
}
// MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApFirst[A, B any](first IO[A], second IO[B]) IO[A] {
return G.MonadApFirst[IO[A], IO[B], IO[func(B) A]](first, second)
return INTA.MonadApFirst(
MonadAp[B, A],
MonadMap[A, func(B) A],
first,
second,
)
}
// ApFirst combines two effectful actions, keeping only the result of the first.
func ApFirst[A, B any](second IO[B]) func(IO[A]) IO[A] {
return G.ApFirst[IO[A], IO[B], IO[func(B) A]](second)
return INTA.ApFirst(
MonadAp[B, A],
MonadMap[A, func(B) A],
second,
)
}
// MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSecond[A, B any](first IO[A], second IO[B]) IO[B] {
return G.MonadApSecond[IO[A], IO[B], IO[func(B) B]](first, second)
return INTA.MonadApSecond(
MonadAp[B, B],
MonadMap[A, func(B) B],
first,
second,
)
}
// ApSecond combines two effectful actions, keeping only the result of the second.
func ApSecond[A, B any](second IO[B]) func(IO[A]) IO[B] {
return G.ApSecond[IO[A], IO[B], IO[func(B) B]](second)
return INTA.ApSecond(
MonadAp[B, B],
MonadMap[A, func(B) B],
second,
)
}
// MonadChainTo composes computations in sequence, ignoring the return value of the first computation
func MonadChainTo[A, B any](fa IO[A], fb IO[B]) IO[B] {
return G.MonadChainTo(fa, fb)
return MonadChain(fa, F.Constant1[A](fb))
}
// ChainTo composes computations in sequence, ignoring the return value of the first computation
func ChainTo[A, B any](fb IO[B]) func(IO[A]) IO[B] {
return G.ChainTo[IO[A]](fb)
return Chain(F.Constant1[A](fb))
}
// Now returns the current timestamp
var Now = G.Now[IO[time.Time]]()
var Now IO[time.Time] = time.Now
// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() IO[A]) IO[A] {
return G.Defer[IO[A]](gen)
return func() A {
return gen()()
}
}
func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B] {
return G.MonadFlap[func(A) B, IO[func(A) B], IO[B], A, B](fab, a)
return INTF.MonadFlap(MonadMap[func(A) B, B], fab, a)
}
func Flap[B, A any](a A) func(IO[func(A) B]) IO[B] {
return G.Flap[func(A) B, IO[func(A) B], IO[B], A, B](a)
return INTF.Flap(Map[func(A) B, B], a)
}
// Delay creates an operation that passes in the value after some delay
func Delay[A any](delay time.Duration) func(IO[A]) IO[A] {
return G.Delay[IO[A]](delay)
return func(ga IO[A]) IO[A] {
return func() A {
time.Sleep(delay)
return ga()
}
}
}
func after(timestamp time.Time) func() {
return func() {
// check if we need to wait
current := time.Now()
if current.Before(timestamp) {
time.Sleep(timestamp.Sub(current))
}
}
}
// After creates an operation that passes after the given timestamp
func After[A any](timestamp time.Time) func(IO[A]) IO[A] {
return G.After[IO[A]](timestamp)
aft := after(timestamp)
return func(ga IO[A]) IO[A] {
return func() A {
// wait as long as necessary
aft()
// execute after wait
return ga()
}
}
}
// WithTime returns an operation that measures the start and end [time.Time] of the operation
func WithTime[A any](a IO[A]) IO[T.Tuple3[A, time.Time, time.Time]] {
return G.WithTime[IO[T.Tuple3[A, time.Time, time.Time]], IO[A]](a)
return func() T.Tuple3[A, time.Time, time.Time] {
t0 := time.Now()
res := a()
t1 := time.Now()
return T.MakeTuple3(res, t0, t1)
}
}
// WithDuration returns an operation that measures the [time.Duration]
func WithDuration[A any](a IO[A]) IO[T.Tuple2[A, time.Duration]] {
return G.WithDuration[IO[T.Tuple2[A, time.Duration]], IO[A]](a)
return func() T.Tuple2[A, time.Duration] {
t0 := time.Now()
res := a()
t1 := time.Now()
return T.MakeTuple2(res, t1.Sub(t0))
}
}

View File

@ -44,7 +44,7 @@ func TestFlatten(t *testing.T) {
}
func TestMemoize(t *testing.T) {
data := Memoize(MakeIO(rand.Int))
data := Memoize(rand.Int)
value1 := data()
value2 := data()

View File

@ -17,10 +17,30 @@ package io
import (
"github.com/IBM/fp-go/v2/internal/monad"
G "github.com/IBM/fp-go/v2/io/generic"
)
// Monad returns the monadic operations for [IO]
func Monad[A, B any]() monad.Monad[A, B, IO[A], IO[B], IO[func(A) B]] {
return G.Monad[A, B, IO[A], IO[B], IO[func(A) B]]()
type (
ioMonad[A, B any] struct{}
IOMonad[A, B any] = monad.Monad[A, B, IO[A], IO[B], IO[func(A) B]]
)
func (o *ioMonad[A, B]) Of(a A) IO[A] {
return Of(a)
}
func (o *ioMonad[A, B]) Map(f func(A) B) func(IO[A]) IO[B] {
return Map(f)
}
func (o *ioMonad[A, B]) Chain(f func(A) IO[B]) func(IO[A]) IO[B] {
return Chain(f)
}
func (o *ioMonad[A, B]) Ap(fa IO[A]) func(IO[func(A) B]) IO[B] {
return Ap[B](fa)
}
// Monad implements the monadic operations for [IO]
func Monad[A, B any]() IOMonad[A, B] {
return &ioMonad[A, B]{}
}

View File

@ -17,10 +17,18 @@ package io
import (
"github.com/IBM/fp-go/v2/internal/pointed"
G "github.com/IBM/fp-go/v2/io/generic"
)
// Pointed returns the monadic operations for [IO]
func Pointed[A any]() pointed.Pointed[A, IO[A]] {
return G.Pointed[A, IO[A]]()
type (
ioPointed[A any] struct{}
IOPointed[A any] = pointed.Pointed[A, IO[A]]
)
func (o *ioPointed[A]) Of(a A) IO[A] {
return Of(a)
}
// Pointed implements the pointedic operations for [IO]
func Pointed[A any]() IOPointed[A] {
return &ioPointed[A]{}
}

View File

@ -33,39 +33,25 @@ func AssertLaws[A, B, C any](t *testing.T,
bc func(B) C,
) func(a A) bool {
return L.AssertLaws(t,
return L.MonadAssertLaws(t,
io.Eq(eqa),
io.Eq(eqb),
io.Eq(eqc),
io.Of[A],
io.Of[B],
io.Of[C],
io.Pointed[C](),
io.Pointed[func(A) A](),
io.Pointed[func(B) C](),
io.Pointed[func(func(A) B) B](),
io.Of[func(A) A],
io.Of[func(A) B],
io.Of[func(B) C],
io.Of[func(func(A) B) B],
io.Functor[func(B) C, func(func(A) B) func(A) C](),
io.MonadMap[A, A],
io.MonadMap[A, B],
io.MonadMap[A, C],
io.MonadMap[B, C],
io.Applicative[func(A) B, B](),
io.Applicative[func(A) B, func(A) C](),
io.MonadMap[func(B) C, func(func(A) B) func(A) C],
io.MonadChain[A, A],
io.MonadChain[A, B],
io.MonadChain[A, C],
io.MonadChain[B, C],
io.MonadAp[A, A],
io.MonadAp[B, A],
io.MonadAp[C, B],
io.MonadAp[C, A],
io.MonadAp[B, func(A) B],
io.MonadAp[func(A) C, func(A) B],
io.Monad[A, A](),
io.Monad[A, B](),
io.Monad[A, C](),
io.Monad[B, C](),
ab,
bc,

View File

@ -18,15 +18,15 @@ package ioeither
import (
ET "github.com/IBM/fp-go/v2/either"
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/ioeither/generic"
IO "github.com/IBM/fp-go/v2/io"
)
// Eq implements the equals predicate for values contained in the IOEither monad
func Eq[E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[IOEither[E, A]] {
return G.Eq[IOEither[E, A]](eq)
return IO.Eq(eq)
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[E, A comparable]() EQ.Eq[IOEither[E, A]] {
return G.FromStrictEquals[IOEither[E, A]]()
return Eq(ET.FromStrictEquals[E, A]())
}

View File

@ -1,32 +0,0 @@
// 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 (
ET "github.com/IBM/fp-go/v2/either"
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/io/generic"
)
// Eq implements the equals predicate for values contained in the IOEither monad
func Eq[GA ~func() ET.Either[E, A], E, A any](eq EQ.Eq[ET.Either[E, A]]) EQ.Eq[GA] {
return G.Eq[GA](eq)
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[GA ~func() ET.Either[E, A], E, A comparable]() EQ.Eq[GA] {
return Eq[GA](ET.FromStrictEquals[E, A]())
}

View File

@ -19,7 +19,9 @@ import (
"time"
ET "github.com/IBM/fp-go/v2/either"
"github.com/IBM/fp-go/v2/internal/eithert"
I "github.com/IBM/fp-go/v2/io"
IOG "github.com/IBM/fp-go/v2/io/generic"
G "github.com/IBM/fp-go/v2/ioeither/generic"
IOO "github.com/IBM/fp-go/v2/iooption"
L "github.com/IBM/fp-go/v2/lazy"
@ -28,26 +30,26 @@ import (
// IOEither represents a synchronous computation that may fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioeitherlte-agt] for more details
type IOEither[E, A any] I.IO[ET.Either[E, A]]
type IOEither[E, A any] = I.IO[ET.Either[E, A]]
func MakeIO[E, A any](f IOEither[E, A]) IOEither[E, A] {
return G.MakeIO(f)
return f
}
func Left[A, E any](l E) IOEither[E, A] {
return G.Left[IOEither[E, A]](l)
return eithert.Left(IOG.MonadOf[IOEither[E, A], ET.Either[E, A]], l)
}
func Right[E, A any](r A) IOEither[E, A] {
return G.Right[IOEither[E, A]](r)
return eithert.Right(IOG.MonadOf[IOEither[E, A], ET.Either[E, A]], r)
}
func Of[E, A any](r A) IOEither[E, A] {
return G.Of[IOEither[E, A]](r)
return Right[E, A](r)
}
func MonadOf[E, A any](r A) IOEither[E, A] {
return G.MonadOf[IOEither[E, A]](r)
return Of[E, A](r)
}
func LeftIO[A, E any](ml I.IO[E]) IOEither[E, A] {

View File

@ -70,9 +70,9 @@ func TestFromOption(t *testing.T) {
func TestChainIOK(t *testing.T) {
f := ChainIOK[string](func(n int) I.IO[string] {
return I.MakeIO(func() string {
return func() string {
return fmt.Sprintf("%d", n)
})
}
})
assert.Equal(t, E.Right[string]("1"), f(Right[string](1))())

View File

@ -17,15 +17,16 @@ package iooption
import (
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/iooption/generic"
IO "github.com/IBM/fp-go/v2/io"
O "github.com/IBM/fp-go/v2/option"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[A any](e EQ.Eq[A]) EQ.Eq[IOOption[A]] {
return G.Eq[IOOption[A]](e)
func Eq[A any](eq EQ.Eq[A]) EQ.Eq[IOOption[A]] {
return IO.Eq(O.Eq(eq))
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[A comparable]() EQ.Eq[IOOption[A]] {
return G.FromStrictEquals[IOOption[A]]()
return Eq(EQ.FromStrictEquals[A]())
}

View File

@ -1,32 +0,0 @@
// 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 (
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/io/generic"
O "github.com/IBM/fp-go/v2/option"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[GA ~func() O.Option[A], A any](e EQ.Eq[A]) EQ.Eq[GA] {
return G.Eq[GA](O.Eq(e))
}
// FromStrictEquals constructs an [EQ.Eq] from the canonical comparison function
func FromStrictEquals[GA ~func() O.Option[A], A comparable]() EQ.Eq[GA] {
return Eq[GA](EQ.FromStrictEquals[A]())
}

View File

@ -28,7 +28,7 @@ import (
// IO represents a synchronous computation that may fail
// refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioeitherlte-agt] for more details
type IOOption[A any] I.IO[O.Option[A]]
type IOOption[A any] = I.IO[O.Option[A]]
func MakeIO[A any](f IOOption[A]) IOOption[A] {
return G.MakeIO(f)

View File

@ -56,9 +56,9 @@ func TestFromOption(t *testing.T) {
func TestChainIOK(t *testing.T) {
f := ChainIOK(func(n int) I.IO[string] {
return I.MakeIO(func() string {
return func() string {
return fmt.Sprintf("%d", n)
})
}
})
assert.Equal(t, O.Of("1"), f(Of(1))())

View File

@ -16,11 +16,11 @@
package lambda
// Y is the Y-combinator based on https://dreamsongs.com/Files/WhyOfY.pdf
func Y[Endo ~func(RecFct) RecFct, RecFct ~func(T) R, T, R any](f Endo) RecFct {
func Y[T, R any](f func(func(T) R) func(T) R) func(T) R {
type internal[RecFct ~func(T) R, T, R any] func(internal[RecFct, T, R]) RecFct
type internal[T, R any] func(internal[T, R]) func(T) R
g := func(h internal[RecFct, T, R]) RecFct {
g := func(h internal[T, R]) func(T) R {
return func(t T) R {
return f(h(h))(t)
}

View File

@ -16,15 +16,15 @@
package lazy
import (
G "github.com/IBM/fp-go/v2/io/generic"
IO "github.com/IBM/fp-go/v2/io"
M "github.com/IBM/fp-go/v2/monoid"
S "github.com/IBM/fp-go/v2/semigroup"
)
func ApplySemigroup[A any](s S.Semigroup[A]) S.Semigroup[Lazy[A]] {
return G.ApplySemigroup[Lazy[A]](s)
return IO.ApplySemigroup(s)
}
func ApplicativeMonoid[A any](m M.Monoid[A]) M.Monoid[Lazy[A]] {
return G.ApplicativeMonoid[Lazy[A]](m)
return IO.ApplicativeMonoid(m)
}

View File

@ -17,10 +17,10 @@ package lazy
import (
EQ "github.com/IBM/fp-go/v2/eq"
G "github.com/IBM/fp-go/v2/io/generic"
IO "github.com/IBM/fp-go/v2/io"
)
// Eq implements the equals predicate for values contained in the IO monad
func Eq[A any](e EQ.Eq[A]) EQ.Eq[Lazy[A]] {
return G.Eq[Lazy[A]](e)
return IO.Eq(e)
}

View File

@ -22,7 +22,7 @@ import (
)
// Lazy represents a synchronous computation without side effects
type Lazy[A any] func() A
type Lazy[A any] = func() A
func MakeLazy[A any](f func() A) Lazy[A] {
return G.MakeIO[Lazy[A]](f)

View File

@ -28,7 +28,7 @@ func ApplicativeMonoid[A, HKTA, HKTFA any](
) Monoid[HKTA] {
return MakeMonoid(
S.ApplySemigroup[A](fmap, fap, m).Concat,
S.ApplySemigroup(fmap, fap, m).Concat,
fof(m.Empty()),
)
}