Skip to content

Commit

Permalink
fix: add missing Memoize to readers
Browse files Browse the repository at this point in the history
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
  • Loading branch information
CarstenLeue committed Sep 20, 2023
1 parent 44c8441 commit 943ae8e
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 2 deletions.
10 changes: 9 additions & 1 deletion context/readerio/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package readerio
import (
"context"

L "github.com/IBM/fp-go/lazy"
R "github.com/IBM/fp-go/readerio/generic"
)

Expand Down Expand Up @@ -54,6 +55,13 @@ func Ask() ReaderIO[context.Context] {
}

// Defer creates an IO by creating a brand new IO via a generator function, each time
func Defer[A any](gen func() ReaderIO[A]) ReaderIO[A] {
func Defer[A any](gen L.Lazy[ReaderIO[A]]) ReaderIO[A] {
return R.Defer[ReaderIO[A]](gen)
}

// Memoize computes the value of the provided [ReaderIO] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[A any](rdr ReaderIO[A]) ReaderIO[A] {
return R.Memoize[ReaderIO[A]](rdr)
}
10 changes: 10 additions & 0 deletions context/readerioeither/generic/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -573,3 +573,13 @@ func MonadAlt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.
func Alt[LAZY ~func() GEA, GEA ~func(context.Context) GIOA, GIOA ~func() E.Either[error, A], A any](second LAZY) func(GEA) GEA {
return RIE.Alt(second)
}

// Memoize computes the value of the provided monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[
GRA ~func(context.Context) GIOA,
GIOA ~func() E.Either[error, A],
A any](rdr GRA) GRA {
return RIE.Memoize[GRA](rdr)
}
7 changes: 7 additions & 0 deletions context/readerioeither/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,3 +213,10 @@ func MonadAlt[A any](first ReaderIOEither[A], second L.Lazy[ReaderIOEither[A]])
func Alt[A any](second L.Lazy[ReaderIOEither[A]]) func(ReaderIOEither[A]) ReaderIOEither[A] {
return G.Alt(second)
}

// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[A any](rdr ReaderIOEither[A]) ReaderIOEither[A] {
return G.Memoize[ReaderIOEither[A]](rdr)
}
2 changes: 1 addition & 1 deletion io/io.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ func Flatten[A any](mma IO[IO[A]]) IO[A] {
return G.Flatten(mma)
}

// Memoize computes the value of the provided IO monad lazily but exactly once
// 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)
}
Expand Down
25 changes: 25 additions & 0 deletions readerio/generic/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
package generic

import (
"sync"

F "github.com/IBM/fp-go/function"
FR "github.com/IBM/fp-go/internal/fromreader"
"github.com/IBM/fp-go/internal/readert"
Expand Down Expand Up @@ -99,3 +101,26 @@ func Defer[GEA ~func(E) GA, GA ~func() A, E, A any](gen func() GEA) GEA {
}
}
}

// Memoize computes the value of the provided reader monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[GEA ~func(E) GA, GA ~func() A, E, A any](rdr GEA) GEA {
// synchronization primitives
var once sync.Once
var result A
// callback
gen := func(e E) func() {
return func() {
result = rdr(e)()
}
}
// returns our memoized wrapper
return func(e E) GA {
io := gen(e)
return func() A {
once.Do(io)
return result
}
}
}
7 changes: 7 additions & 0 deletions readerio/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,3 +75,10 @@ func ChainIOK[E, A, B any](f func(A) IO.IO[B]) func(ReaderIO[E, A]) ReaderIO[E,
func Defer[E, A any](gen func() ReaderIO[E, A]) ReaderIO[E, A] {
return G.Defer[ReaderIO[E, A]](gen)
}

// Memoize computes the value of the provided [ReaderIO] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[E, A any](rdr ReaderIO[E, A]) ReaderIO[E, A] {
return G.Memoize[ReaderIO[E, A]](rdr)
}
8 changes: 8 additions & 0 deletions readerioeither/generic/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -406,3 +406,11 @@ func TryCatch[GEA ~func(R) GA, GA ~func() ET.Either[E, A], R, E, A any](f func(R
return IOE.TryCatch[GA](f(r), onThrow)
}
}

// Memoize computes the value of the provided monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[
GEA ~func(R) GIOA, GIOA ~func() ET.Either[E, A], R, E, A any](rdr GEA) GEA {
return G.Memoize[GEA](rdr)
}
8 changes: 8 additions & 0 deletions readerioeither/reader.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,3 +264,11 @@ func MonadAlt[R, E, A any](first ReaderIOEither[R, E, A], second L.Lazy[ReaderIO
func Alt[R, E, A any](second L.Lazy[ReaderIOEither[R, E, A]]) func(ReaderIOEither[R, E, A]) ReaderIOEither[R, E, A] {
return G.Alt(second)
}

// Memoize computes the value of the provided [ReaderIOEither] monad lazily but exactly once
// The context used to compute the value is the context of the first call, so do not use this
// method if the value has a functional dependency on the content of the context
func Memoize[
R, E, A any](rdr ReaderIOEither[R, E, A]) ReaderIOEither[R, E, A] {
return G.Memoize[ReaderIOEither[R, E, A]](rdr)
}

0 comments on commit 943ae8e

Please sign in to comment.