diff --git a/v2/array/generic/bind.go b/v2/array/generic/bind.go index 6f615f8..1d928f6 100644 --- a/v2/array/generic/bind.go +++ b/v2/array/generic/bind.go @@ -75,7 +75,39 @@ func BindTo[GS1 ~[]S1, GT ~[]T, S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. For arrays, this produces the cartesian product. +// +// Example: +// +// type State struct { +// X int +// Y string +// } +// +// // These operations are independent and can be combined with ApS +// xValues := []int{1, 2} +// yValues := []string{"a", "b"} +// +// result := F.Pipe2( +// generic.Do[[]State, State](State{}), +// generic.ApS[[]State, []State, []int, State, State, int]( +// func(x int) func(State) State { +// return func(s State) State { s.X = x; return s } +// }, +// xValues, +// ), +// generic.ApS[[]State, []State, []string, State, State, string]( +// func(y string) func(State) State { +// return func(s State) State { s.Y = y; return s } +// }, +// yValues, +// ), +// ) // [{1,"a"}, {1,"b"}, {2,"a"}, {2,"b"}] func ApS[GS1 ~[]S1, GS2 ~[]S2, GT ~[]T, S1, S2, T any]( setter func(T) func(S1) S2, fa GT, diff --git a/v2/context/readereither/bind.go b/v2/context/readereither/bind.go index 2554060..a3e9518 100644 --- a/v2/context/readereither/bind.go +++ b/v2/context/readereither/bind.go @@ -59,7 +59,43 @@ func BindTo[S1, T any]( return G.BindTo[ReaderEither[S1], ReaderEither[T], context.Context, error, S1, T](setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// UserID string +// TenantID string +// } +// +// // These operations are independent and can be combined with ApS +// getUserID := func(ctx context.Context) either.Either[error, string] { +// return either.Right[error](ctx.Value("userID").(string)) +// } +// getTenantID := func(ctx context.Context) either.Either[error, string] { +// return either.Right[error](ctx.Value("tenantID").(string)) +// } +// +// result := F.Pipe2( +// readereither.Do(State{}), +// readereither.ApS( +// func(uid string) func(State) State { +// return func(s State) State { s.UserID = uid; return s } +// }, +// getUserID, +// ), +// readereither.ApS( +// func(tid string) func(State) State { +// return func(s State) State { s.TenantID = tid; return s } +// }, +// getTenantID, +// ), +// ) func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderEither[T], diff --git a/v2/context/readerioeither/bind.go b/v2/context/readerioeither/bind.go index 37fbe2b..94fecf8 100644 --- a/v2/context/readerioeither/bind.go +++ b/v2/context/readerioeither/bind.go @@ -75,7 +75,47 @@ func BindTo[S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// User User +// Config Config +// } +// +// // These operations are independent and can be combined with ApS +// getUser := func(ctx context.Context) ioeither.IOEither[error, User] { +// return ioeither.TryCatch(func() (User, error) { +// return fetchUser(ctx) +// }) +// } +// getConfig := func(ctx context.Context) ioeither.IOEither[error, Config] { +// return ioeither.TryCatch(func() (Config, error) { +// return fetchConfig(ctx) +// }) +// } +// +// result := F.Pipe2( +// readerioeither.Do(State{}), +// readerioeither.ApS( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// readerioeither.ApS( +// func(cfg Config) func(State) State { +// return func(s State) State { s.Config = cfg; return s } +// }, +// getConfig, +// ), +// ) func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIOEither[T], diff --git a/v2/identity/bind.go b/v2/identity/bind.go index b473a28..86b84ca 100644 --- a/v2/identity/bind.go +++ b/v2/identity/bind.go @@ -75,7 +75,36 @@ func BindTo[S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// X int +// Y int +// } +// +// // These operations are independent and can be combined with ApS +// result := F.Pipe2( +// identity.Do(State{}), +// identity.ApS( +// func(x int) func(State) State { +// return func(s State) State { s.X = x; return s } +// }, +// 42, +// ), +// identity.ApS( +// func(y int) func(State) State { +// return func(s State) State { s.Y = y; return s } +// }, +// 100, +// ), +// ) // State{X: 42, Y: 100} func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa T, diff --git a/v2/ioeither/bind.go b/v2/ioeither/bind.go index c7b79e6..d0ffed2 100644 --- a/v2/ioeither/bind.go +++ b/v2/ioeither/bind.go @@ -75,7 +75,39 @@ func BindTo[E, S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// User User +// Posts []Post +// } +// +// // These operations are independent and can be combined with ApS +// getUser := ioeither.Right[error](User{ID: 1, Name: "Alice"}) +// getPosts := ioeither.Right[error]([]Post{{ID: 1, Title: "Hello"}}) +// +// result := F.Pipe2( +// ioeither.Do[error](State{}), +// ioeither.ApS( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// ioeither.ApS( +// func(posts []Post) func(State) State { +// return func(s State) State { s.Posts = posts; return s } +// }, +// getPosts, +// ), +// ) func ApS[E, S1, S2, T any]( setter func(T) func(S1) S2, fa IOEither[E, T], diff --git a/v2/iooption/bind.go b/v2/iooption/bind.go index 557b77c..92547c2 100644 --- a/v2/iooption/bind.go +++ b/v2/iooption/bind.go @@ -75,7 +75,39 @@ func BindTo[S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// Name string +// Age int +// } +// +// // These operations are independent and can be combined with ApS +// getName := iooption.Some("Alice") +// getAge := iooption.Some(30) +// +// result := F.Pipe2( +// iooption.Do(State{}), +// iooption.ApS( +// func(name string) func(State) State { +// return func(s State) State { s.Name = name; return s } +// }, +// getName, +// ), +// iooption.ApS( +// func(age int) func(State) State { +// return func(s State) State { s.Age = age; return s } +// }, +// getAge, +// ), +// ) func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa IOOption[T], diff --git a/v2/iterator/stateless/bind.go b/v2/iterator/stateless/bind.go index 5774bca..93d4978 100644 --- a/v2/iterator/stateless/bind.go +++ b/v2/iterator/stateless/bind.go @@ -57,7 +57,39 @@ func BindTo[S1, T any]( return G.BindTo[Iterator[S1], Iterator[T], S1, T](setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// X int +// Y int +// } +// +// // These operations are independent and can be combined with ApS +// xValues := stateless.Of(1, 2, 3) +// yValues := stateless.Of(10, 20) +// +// result := F.Pipe2( +// stateless.Do(State{}), +// stateless.ApS( +// func(x int) func(State) State { +// return func(s State) State { s.X = x; return s } +// }, +// xValues, +// ), +// stateless.ApS( +// func(y int) func(State) State { +// return func(s State) State { s.Y = y; return s } +// }, +// yValues, +// ), +// ) // Produces all combinations: {1,10}, {1,20}, {2,10}, {2,20}, {3,10}, {3,20} func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa Iterator[T], diff --git a/v2/iterator/stateless/generic/bind.go b/v2/iterator/stateless/generic/bind.go index bce0b47..27191ac 100644 --- a/v2/iterator/stateless/generic/bind.go +++ b/v2/iterator/stateless/generic/bind.go @@ -78,7 +78,39 @@ func BindTo[GS1 ~func() O.Option[P.Pair[GS1, S1]], GA ~func() O.Option[P.Pair[GA ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. For iterators, this produces the cartesian product. +// +// Example: +// +// type State struct { +// X int +// Y string +// } +// +// // These operations are independent and can be combined with ApS +// xIter := generic.Of[Iterator[int]](1, 2, 3) +// yIter := generic.Of[Iterator[string]]("a", "b") +// +// result := F.Pipe2( +// generic.Do[Iterator[State]](State{}), +// generic.ApS[Iterator[func(int) State], Iterator[State], Iterator[State], Iterator[int], State, State, int]( +// func(x int) func(State) State { +// return func(s State) State { s.X = x; return s } +// }, +// xIter, +// ), +// generic.ApS[Iterator[func(string) State], Iterator[State], Iterator[State], Iterator[string], State, State, string]( +// func(y string) func(State) State { +// return func(s State) State { s.Y = y; return s } +// }, +// yIter, +// ), +// ) // Produces: {1,"a"}, {1,"b"}, {2,"a"}, {2,"b"}, {3,"a"}, {3,"b"} func ApS[GAS2 ~func() O.Option[P.Pair[GAS2, func(A) S2]], GS1 ~func() O.Option[P.Pair[GS1, S1]], GS2 ~func() O.Option[P.Pair[GS2, S2]], GA ~func() O.Option[P.Pair[GA, A]], S1, S2, A any]( setter func(A) func(S1) S2, fa GA, diff --git a/v2/lazy/bind.go b/v2/lazy/bind.go index c635c91..7b03893 100644 --- a/v2/lazy/bind.go +++ b/v2/lazy/bind.go @@ -57,7 +57,39 @@ func BindTo[S1, T any]( return io.BindTo(setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// Config Config +// Data Data +// } +// +// // These operations are independent and can be combined with ApS +// getConfig := lazy.MakeLazy(func() Config { return loadConfig() }) +// getData := lazy.MakeLazy(func() Data { return loadData() }) +// +// result := F.Pipe2( +// lazy.Do(State{}), +// lazy.ApS( +// func(cfg Config) func(State) State { +// return func(s State) State { s.Config = cfg; return s } +// }, +// getConfig, +// ), +// lazy.ApS( +// func(data Data) func(State) State { +// return func(s State) State { s.Data = data; return s } +// }, +// getData, +// ), +// ) func ApS[S1, S2, T any]( setter func(T) func(S1) S2, fa Lazy[T], diff --git a/v2/readereither/bind.go b/v2/readereither/bind.go index 35b7143..11045fd 100644 --- a/v2/readereither/bind.go +++ b/v2/readereither/bind.go @@ -57,7 +57,47 @@ func BindTo[R, E, S1, T any]( return G.BindTo[ReaderEither[R, E, S1], ReaderEither[R, E, T], R, E, S1, T](setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// User User +// Config Config +// } +// type Env struct { +// UserService UserService +// ConfigService ConfigService +// } +// +// // These operations are independent and can be combined with ApS +// getUser := readereither.Asks(func(env Env) either.Either[error, User] { +// return env.UserService.GetUser() +// }) +// getConfig := readereither.Asks(func(env Env) either.Either[error, Config] { +// return env.ConfigService.GetConfig() +// }) +// +// result := F.Pipe2( +// readereither.Do[Env, error](State{}), +// readereither.ApS( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// readereither.ApS( +// func(cfg Config) func(State) State { +// return func(s State) State { s.Config = cfg; return s } +// }, +// getConfig, +// ), +// ) func ApS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderEither[R, E, T], diff --git a/v2/readereither/generic/bind.go b/v2/readereither/generic/bind.go index 55c7d05..d7467cc 100644 --- a/v2/readereither/generic/bind.go +++ b/v2/readereither/generic/bind.go @@ -76,7 +76,47 @@ func BindTo[GS1 ~func(R) ET.Either[E, S1], GT ~func(R) ET.Either[E, T], R, E, S1 ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// Config Config +// User User +// } +// type Env struct { +// ConfigService ConfigService +// UserService UserService +// } +// +// // These operations are independent and can be combined with ApS +// getConfig := func(env Env) either.Either[error, Config] { +// return env.ConfigService.Load() +// } +// getUser := func(env Env) either.Either[error, User] { +// return env.UserService.GetCurrent() +// } +// +// result := F.Pipe2( +// generic.Do[ReaderEither[Env, error, State], Env, error, State](State{}), +// generic.ApS[...]( +// func(cfg Config) func(State) State { +// return func(s State) State { s.Config = cfg; return s } +// }, +// getConfig, +// ), +// generic.ApS[...]( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// ) func ApS[GS1 ~func(R) ET.Either[E, S1], GS2 ~func(R) ET.Either[E, S2], GT ~func(R) ET.Either[E, T], R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa GT, diff --git a/v2/readerio/bind.go b/v2/readerio/bind.go index 85b920c..232280f 100644 --- a/v2/readerio/bind.go +++ b/v2/readerio/bind.go @@ -75,7 +75,47 @@ func BindTo[R, S1, T any]( ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// Host string +// Port int +// } +// type Config struct { +// DefaultHost string +// DefaultPort int +// } +// +// // These operations are independent and can be combined with ApS +// getHost := readerio.Asks(func(c Config) io.IO[string] { +// return io.Of(c.DefaultHost) +// }) +// getPort := readerio.Asks(func(c Config) io.IO[int] { +// return io.Of(c.DefaultPort) +// }) +// +// result := F.Pipe2( +// readerio.Do[Config](State{}), +// readerio.ApS( +// func(host string) func(State) State { +// return func(s State) State { s.Host = host; return s } +// }, +// getHost, +// ), +// readerio.ApS( +// func(port int) func(State) State { +// return func(s State) State { s.Port = port; return s } +// }, +// getPort, +// ), +// ) func ApS[R, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIO[R, T], diff --git a/v2/readerioeither/bind.go b/v2/readerioeither/bind.go index 6dcdfdb..6170294 100644 --- a/v2/readerioeither/bind.go +++ b/v2/readerioeither/bind.go @@ -58,7 +58,47 @@ func BindTo[R, E, S1, T any]( return G.BindTo[ReaderIOEither[R, E, S1], ReaderIOEither[R, E, T], IOE.IOEither[E, S1], IOE.IOEither[E, T], R, E, S1, T](setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// User User +// Posts []Post +// } +// type Env struct { +// UserRepo UserRepository +// PostRepo PostRepository +// } +// +// // These operations are independent and can be combined with ApS +// getUser := readerioeither.Asks(func(env Env) ioeither.IOEither[error, User] { +// return env.UserRepo.FindUser() +// }) +// getPosts := readerioeither.Asks(func(env Env) ioeither.IOEither[error, []Post] { +// return env.PostRepo.FindPosts() +// }) +// +// result := F.Pipe2( +// readerioeither.Do[Env, error](State{}), +// readerioeither.ApS( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// readerioeither.ApS( +// func(posts []Post) func(State) State { +// return func(s State) State { s.Posts = posts; return s } +// }, +// getPosts, +// ), +// ) func ApS[R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa ReaderIOEither[R, E, T], diff --git a/v2/readerioeither/generic/bind.go b/v2/readerioeither/generic/bind.go index 812871d..0ed55c2 100644 --- a/v2/readerioeither/generic/bind.go +++ b/v2/readerioeither/generic/bind.go @@ -76,7 +76,47 @@ func BindTo[GRS1 ~func(R) GS1, GRT ~func(R) GT, GS1 ~func() either.Either[E, S1] ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// User User +// Config Config +// } +// type Env struct { +// UserRepo UserRepository +// ConfigRepo ConfigRepository +// } +// +// // These operations are independent and can be combined with ApS +// getUser := func(env Env) ioeither.IOEither[error, User] { +// return env.UserRepo.FindUser() +// } +// getConfig := func(env Env) ioeither.IOEither[error, Config] { +// return env.ConfigRepo.LoadConfig() +// } +// +// result := F.Pipe2( +// generic.Do[ReaderIOEither[Env, error, State], IOEither[error, State], Env, error, State](State{}), +// generic.ApS[...]( +// func(user User) func(State) State { +// return func(s State) State { s.User = user; return s } +// }, +// getUser, +// ), +// generic.ApS[...]( +// func(cfg Config) func(State) State { +// return func(s State) State { s.Config = cfg; return s } +// }, +// getConfig, +// ), +// ) func ApS[GRTS1 ~func(R) GTS1, GRS1 ~func(R) GS1, GRS2 ~func(R) GS2, GRT ~func(R) GT, GTS1 ~func() either.Either[E, func(T) S2], GS1 ~func() either.Either[E, S1], GS2 ~func() either.Either[E, S2], GT ~func() either.Either[E, T], R, E, S1, S2, T any]( setter func(T) func(S1) S2, fa GRT, diff --git a/v2/record/bind.go b/v2/record/bind.go index 6255185..d8c6275 100644 --- a/v2/record/bind.go +++ b/v2/record/bind.go @@ -51,7 +51,39 @@ func BindTo[S1, T any, K comparable](setter func(T) S1) func(map[K]T) map[K]S1 { return G.BindTo[map[K]S1, map[K]T, K, S1, T](setter) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. +// +// Example: +// +// type State struct { +// Name string +// Count int +// } +// +// // These operations are independent and can be combined with ApS +// names := map[string]string{"a": "Alice", "b": "Bob"} +// counts := map[string]int{"a": 10, "b": 20} +// +// result := F.Pipe2( +// record.Do[string, State](), +// record.ApS(monoid.Record[string, State]())( +// func(name string) func(State) State { +// return func(s State) State { s.Name = name; return s } +// }, +// names, +// ), +// record.ApS(monoid.Record[string, State]())( +// func(count int) func(State) State { +// return func(s State) State { s.Count = count; return s } +// }, +// counts, +// ), +// ) // map[string]State{"a": {Name: "Alice", Count: 10}, "b": {Name: "Bob", Count: 20}} func ApS[S1, T any, K comparable, S2 any](m Mo.Monoid[map[K]S2]) func(setter func(T) func(S1) S2, fa map[K]T) func(map[K]S1) map[K]S2 { return G.ApS[map[K]S1, map[K]S2, map[K]T, K, S1, S2, T](m) } diff --git a/v2/record/generic/bind.go b/v2/record/generic/bind.go index 29fe63b..30e588b 100644 --- a/v2/record/generic/bind.go +++ b/v2/record/generic/bind.go @@ -72,7 +72,43 @@ func BindTo[GS1 ~map[K]S1, GT ~map[K]T, K comparable, S1, T any](setter func(T) ) } -// ApS attaches a value to a context [S1] to produce a context [S2] by considering the context and the value concurrently +// ApS attaches a value to a context [S1] to produce a context [S2] by considering +// the context and the value concurrently (using Applicative rather than Monad). +// This allows independent computations to be combined without one depending on the result of the other. +// +// Unlike Bind, which sequences operations, ApS can be used when operations are independent +// and can conceptually run in parallel. For records, this merges values by key. +// +// Example: +// +// type State struct { +// Name string +// Score int +// } +// +// // These operations are independent and can be combined with ApS +// names := map[string]string{"player1": "Alice", "player2": "Bob"} +// scores := map[string]int{"player1": 100, "player2": 200} +// +// result := F.Pipe2( +// generic.Do[map[string]State, string, State](), +// generic.ApS[map[string]State, map[string]State, map[string]string, string, State, State, string]( +// monoid.Record[string, State](), +// )( +// func(name string) func(State) State { +// return func(s State) State { s.Name = name; return s } +// }, +// names, +// ), +// generic.ApS[map[string]State, map[string]State, map[string]int, string, State, State, int]( +// monoid.Record[string, State](), +// )( +// func(score int) func(State) State { +// return func(s State) State { s.Score = score; return s } +// }, +// scores, +// ), +// ) // map[string]State{"player1": {Name: "Alice", Score: 100}, "player2": {Name: "Bob", Score: 200}} func ApS[GS1 ~map[K]S1, GS2 ~map[K]S2, GT ~map[K]T, K comparable, S1, S2, T any](m Mo.Monoid[GS2]) func(setter func(T) func(S1) S2, fa GT) func(GS1) GS2 { a := Ap[GS2, map[K]func(T) S2, GT, K, S2, T](m) return func(setter func(T) func(S1) S2, fa GT) func(GS1) GS2 {