Documentation
¶
Overview ¶
Package io provides the IO monad, representing synchronous computations that cannot fail.
IO is a lazy computation that encapsulates side effects and ensures referential transparency. Unlike functions that execute immediately, IO values describe computations that will be executed when explicitly invoked.
Fantasy Land Specification ¶
This implementation corresponds to the Fantasy Land IO type: https://github.com/fantasyland/fantasy-land
Implemented Fantasy Land algebras:
- Functor: https://github.com/fantasyland/fantasy-land#functor
- Apply: https://github.com/fantasyland/fantasy-land#apply
- Applicative: https://github.com/fantasyland/fantasy-land#applicative
- Chain: https://github.com/fantasyland/fantasy-land#chain
- Monad: https://github.com/fantasyland/fantasy-land#monad
Core Concepts ¶
The IO type is defined as a function that takes no arguments and returns a value:
type IO[A any] = func() A
This simple definition provides powerful guarantees:
- Lazy evaluation: computations are not executed until explicitly called
- Composability: IO operations can be combined without executing them
- Referential transparency: IO values can be safely reused and passed around
Basic Usage ¶
// Creating IO values
greeting := io.Of("Hello, World!")
timestamp := io.Now
// Transforming values with Map
upper := io.Map(strings.ToUpper)(greeting)
// Chaining computations with Chain
result := io.Chain(func(s string) io.IO[int] {
return io.Of(len(s))
})(greeting)
// Executing the computation
value := result() // Only now does the computation run
Monadic Operations ¶
IO implements the Monad interface, providing:
- Of: Wrap a pure value in IO
- Map: Transform the result of a computation
- Chain (FlatMap): Sequence computations that return IO
- Ap: Apply a function wrapped in IO to a value wrapped in IO
Parallel vs Sequential Execution ¶
IO supports both parallel and sequential execution of applicative operations:
- Ap/MonadAp: Parallel execution (default)
- ApSeq/MonadApSeq: Sequential execution
- ApPar/MonadApPar: Explicit parallel execution
Time-based Operations ¶
// Delay execution delayed := io.Delay(time.Second)(computation) // Execute after a specific time scheduled := io.After(timestamp)(computation) // Measure execution time withDuration := io.WithDuration(computation) withTime := io.WithTime(computation)
Resource Management ¶
IO provides utilities for safe resource management:
// Bracket ensures cleanup
result := io.Bracket(
acquire,
use,
release,
)
// WithResource simplifies resource patterns
withFile := io.WithResource(openFile, closeFile)
result := withFile(func(f *os.File) io.IO[Data] {
return readData(f)
})
Retry Logic ¶
// Retry with exponential backoff
result := io.Retrying(
retry.ExponentialBackoff(time.Second, 5),
func(status retry.RetryStatus) io.IO[Result] {
return fetchData()
},
func(r Result) bool { return r.ShouldRetry },
)
Traversal Operations ¶
IO provides utilities for working with collections:
- TraverseArray: Apply IO-returning function to array elements
- TraverseRecord: Apply IO-returning function to map values
- SequenceArray: Convert []IO[A] to IO[[]A]
- SequenceRecord: Convert map[K]IO[A] to IO[map[K]A]
Both parallel and sequential variants are available (e.g., TraverseArraySeq).
Do Notation ¶
IO supports do-notation style composition for imperative-looking code:
result := pipe.Pipe3(
io.Do(State{}),
io.Bind("user", func(s State) io.IO[User] {
return fetchUser(s.userId)
}),
io.Bind("posts", func(s State) io.IO[[]Post] {
return fetchPosts(s.user.Id)
}),
io.Map(func(s State) Result {
return formatResult(s.user, s.posts)
}),
)
Logging and Debugging ¶
// Log values during computation
logged := io.ChainFirst(io.Logger()("Fetched user"))(fetchUser)
// Printf-style logging
logged := io.ChainFirst(io.Printf("User: %+v"))(fetchUser)
Subpackages ¶
- io/file: File system operations returning IO
- io/generic: Generic IO utilities and type classes
- io/testing: Testing utilities for IO laws
Relationship to Other Monads ¶
IO is the simplest effect monad in the fp-go library:
- IOEither: IO that can fail (combines IO with Either)
- IOOption: IO that may not return a value (combines IO with Option)
- ReaderIO: IO with dependency injection (combines Reader with IO)
- ReaderIOEither: Full effect system with DI and error handling
Package io provides the IO monad for managing side effects in a functional way. This file contains retry combinators for the IO monad.
Index ¶
- func Eq[A any](e EQ.Eq[A]) EQ.Eq[IO[A]]
- func FromStrictEquals[A comparable]() EQ.Eq[IO[A]]
- func Logger[A any](loggers ...*log.Logger) func(string) Kleisli[A, A]
- func Run[A any](fa IO[A]) A
- func TraverseParTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) ...
- func TraverseParTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
- func TraverseParTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
- func TraverseParTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func TraverseParTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func TraverseParTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) ...
- func TraverseParTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) ...
- func TraverseParTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) ...
- func TraverseParTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) ...
- func TraverseSeqTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) ...
- func TraverseSeqTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
- func TraverseSeqTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
- func TraverseSeqTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func TraverseSeqTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func TraverseSeqTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) ...
- func TraverseSeqTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) ...
- func TraverseSeqTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) ...
- func TraverseSeqTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) ...
- func TraverseTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) ...
- func TraverseTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
- func TraverseTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
- func TraverseTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func TraverseTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func TraverseTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) ...
- func TraverseTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) ...
- func TraverseTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) ...
- func TraverseTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], ...](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) ...
- func WithLock[A any](lock IO[context.CancelFunc]) func(fa IO[A]) IO[A]
- type Consumer
- type IO
- func Bracket[A, B, ANY any](acquire IO[A], use Kleisli[A, B], release func(A, B) IO[ANY]) IO[B]
- func Defer[A any](gen func() IO[A]) IO[A]
- func Do[S any](empty S) IO[S]
- func Flatten[A any](mma IO[IO[A]]) IO[A]
- func FromIO[A any](a IO[A]) IO[A]
- func FromImpure[ANY ~func()](f ANY) IO[any]
- func Memoize[A any](ma IO[A]) IO[A]
- func MonadAp[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]
- func MonadApFirst[A, B any](first IO[A], second IO[B]) IO[A]
- func MonadApPar[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]
- func MonadApSecond[A, B any](first IO[A], second IO[B]) IO[B]
- func MonadApSeq[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]
- func MonadChain[A, B any](fa IO[A], f Kleisli[A, B]) IO[B]
- func MonadChainFirst[A, B any](fa IO[A], f Kleisli[A, B]) IO[A]
- func MonadChainTo[A, B any](fa IO[A], fb IO[B]) IO[B]
- func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B]
- func MonadMap[A, B any](fa IO[A], f func(A) B) IO[B]
- func MonadMapTo[A, B any](fa IO[A], b B) IO[B]
- func MonadOf[A any](a A) IO[A]
- func MonadTraverseArray[A, B any](tas []A, f Kleisli[A, B]) IO[[]B]
- func MonadTraverseArraySeq[A, B any](tas []A, f Kleisli[A, B]) IO[[]B]
- func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f Kleisli[A, B]) IO[map[K]B]
- func MonadTraverseRecordSeq[K comparable, A, B any](tas map[K]A, f Kleisli[A, B]) IO[map[K]B]
- func Of[A any](a A) IO[A]
- func Retrying[A any](policy R.RetryPolicy, action Kleisli[R.RetryStatus, A], check Predicate[A]) IO[A]
- func SequenceArray[A any](tas []IO[A]) IO[[]A]
- func SequenceArraySeq[A any](tas []IO[A]) IO[[]A]
- func SequenceParT1[T1 any](t1 IO[T1]) IO[tuple.Tuple1[T1]]
- func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceParT2[T1, T2 any](t1 IO[T1], t2 IO[T2]) IO[tuple.Tuple2[T1, T2]]
- func SequenceParT3[T1, T2, T3 any](t1 IO[T1], t2 IO[T2], t3 IO[T3]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceParT4[T1, T2, T3, T4 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceParT5[T1, T2, T3, T4, T5 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceParT6[T1, T2, T3, T4, T5, T6 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func SequenceParTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]
- func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceParTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]
- func SequenceParTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceParTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceParTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A]
- func SequenceRecordSeq[K comparable, A any](tas map[K]IO[A]) IO[map[K]A]
- func SequenceSeqT1[T1 any](t1 IO[T1]) IO[tuple.Tuple1[T1]]
- func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceSeqT2[T1, T2 any](t1 IO[T1], t2 IO[T2]) IO[tuple.Tuple2[T1, T2]]
- func SequenceSeqT3[T1, T2, T3 any](t1 IO[T1], t2 IO[T2], t3 IO[T3]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceSeqT4[T1, T2, T3, T4 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceSeqT5[T1, T2, T3, T4, T5 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func SequenceSeqTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]
- func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceSeqTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]
- func SequenceSeqTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceSeqTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func SequenceT1[T1 any](t1 IO[T1]) IO[tuple.Tuple1[T1]]
- func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceT2[T1, T2 any](t1 IO[T1], t2 IO[T2]) IO[tuple.Tuple2[T1, T2]]
- func SequenceT3[T1, T2, T3 any](t1 IO[T1], t2 IO[T2], t3 IO[T3]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceT4[T1, T2, T3, T4 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceT5[T1, T2, T3, T4, T5 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceT6[T1, T2, T3, T4, T5, T6 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func SequenceTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]
- func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](...) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
- func SequenceTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]
- func SequenceTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
- func SequenceTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
- func SequenceTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
- func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
- func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
- func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
- func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](...) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
- func WithDuration[A any](a IO[A]) IO[Pair[time.Duration, A]]
- func WithTime[A any](a IO[A]) IO[Pair[Pair[time.Time, time.Time], A]]
- type IOApplicative
- type IOFunctor
- type IOMonad
- type IOPointed
- type Kleisli
- func FromConsumer[A any](c Consumer[A]) Kleisli[A, Void]
- func LogGo[A any](prefix string) Kleisli[A, A]
- func Logf[A any](prefix string) Kleisli[A, A]
- func PrintGo[A any](prefix string) Kleisli[A, A]
- func Printf[A any](prefix string) Kleisli[A, A]
- func TailRec[A, B any](f Kleisli[A, Trampoline[A, B]]) Kleisli[A, B]
- func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]
- func TraverseArraySeq[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]
- func TraverseArrayWithIndex[A, B any](f func(int, A) IO[B]) Kleisli[[]A, []B]
- func TraverseArrayWithIndexSeq[A, B any](f func(int, A) IO[B]) Kleisli[[]A, []B]
- func TraverseIter[A, B any](f Kleisli[A, B]) Kleisli[Seq[A], Seq[B]]
- func TraverseParTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
- func TraverseRecord[K comparable, A, B any](f Kleisli[A, B]) Kleisli[map[K]A, map[K]B]
- func TraverseRecordSeq[K comparable, A, B any](f Kleisli[A, B]) Kleisli[map[K]A, map[K]B]
- func TraverseRecordWithIndeSeq[K comparable, A, B any](f func(K, A) IO[B]) Kleisli[map[K]A, map[K]B]
- func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) Kleisli[map[K]A, map[K]B]
- func TraverseSeqTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
- func TraverseTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
- func WithResource[R, A, ANY any](onCreate IO[R], onRelease func(R) IO[ANY]) Kleisli[Kleisli[R, A], A]
- type Monoid
- type Operator
- func After[A any](timestamp time.Time) Operator[A, A]
- func Ap[B, A any](ma IO[A]) Operator[func(A) B, B]
- func ApFirst[A, B any](second IO[B]) Operator[A, A]
- func ApPar[B, A any](ma IO[A]) Operator[func(A) B, B]
- func ApS[S1, S2, T any](setter func(T) func(S1) S2, fa IO[T]) Operator[S1, S2]
- func ApSL[S, T any](lens L.Lens[S, T], fa IO[T]) Operator[S, S]
- func ApSecond[A, B any](second IO[B]) Operator[A, B]
- func ApSeq[B, A any](ma IO[A]) Operator[func(A) B, B]
- func Bind[S1, S2, T any](setter func(T) func(S1) S2, f Kleisli[S1, T]) Operator[S1, S2]
- func BindL[S, T any](lens L.Lens[S, T], f Kleisli[T, T]) Operator[S, S]
- func BindTo[S1, T any](setter func(T) S1) Operator[T, S1]
- func Chain[A, B any](f Kleisli[A, B]) Operator[A, B]
- func ChainConsumer[A any](c Consumer[A]) Operator[A, Void]
- func ChainFirst[A, B any](f Kleisli[A, B]) Operator[A, A]
- func ChainTo[A, B any](fb IO[B]) Operator[A, B]
- func Delay[A any](delay time.Duration) Operator[A, A]
- func Flap[B, A any](a A) Operator[func(A) B, B]
- func Let[S1, S2, T any](setter func(T) func(S1) S2, f func(S1) T) Operator[S1, S2]
- func LetL[S, T any](lens L.Lens[S, T], f func(T) T) Operator[S, S]
- func LetTo[S1, S2, T any](setter func(T) func(S1) S2, b T) Operator[S1, S2]
- func LetToL[S, T any](lens L.Lens[S, T], b T) Operator[S, S]
- func Map[A, B any](f func(A) B) Operator[A, B]
- func MapTo[A, B any](b B) Operator[A, B]
- type Pair
- type Predicate
- type RetryStatus
- type Semigroup
- type Seq
- type Trampoline
- type Void
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Eq ¶
Eq implements the equals predicate for values contained in the IO monad. It lifts an Eq[A] into an Eq[IO[A]] by executing both IO computations and comparing their results.
Example:
intEq := eq.FromStrictEquals[int]() ioEq := io.Eq(intEq) result := ioEq.Equals(io.Of(42), io.Of(42)) // true
func FromStrictEquals ¶
func FromStrictEquals[A comparable]() EQ.Eq[IO[A]]
FromStrictEquals constructs an Eq[IO[A]] from the canonical comparison function for comparable types. This is a convenience function that combines Eq with the standard equality operator.
Example:
ioEq := io.FromStrictEquals[int]() result := ioEq.Equals(io.Of(42), io.Of(42)) // true
func Logger ¶
Logger constructs a logger function that can be used with ChainFirst or similar operations. It logs values using the provided loggers (or the default logger if none provided).
Example:
result := pipe.Pipe2(
fetchUser(),
io.ChainFirst(io.Logger[User]()("Fetched user")),
processUser,
)
func Run ¶ added in v2.1.1
Run executes an IO computation and returns its result.
This function is the primary way to execute IO computations. It takes an IO[A] (a lazy computation) and immediately evaluates it, returning the computed value.
Run is the bridge between the pure functional world (where computations are described but not executed) and the imperative world (where side effects occur). It should typically be called at the edges of your application, such as in main() or in test code.
Parameters:
- fa: The IO computation to execute
Returns:
- The result of executing the IO computation
Example:
// Create a lazy computation
greeting := io.Of("Hello, World!")
// Execute it and get the result
result := io.Run(greeting) // result == "Hello, World!"
Example with side effects:
// Create a computation that prints and returns a value
computation := func() string {
fmt.Println("Computing...")
return "Done"
}
// Nothing is printed yet
io := io.MakeIO(computation)
// Now the computation runs and "Computing..." is printed
result := io.Run(io) // result == "Done"
Example with composition:
result := io.Run(
pipe.Pipe2(
io.Of(5),
io.Map(func(x int) int { return x * 2 }),
io.Map(func(x int) int { return x + 1 }),
),
) // result == 11
Note: Run should be used sparingly in application code. Prefer composing IO computations and only calling Run at the application boundaries.
func TraverseParTuple10 ¶
func TraverseParTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], F10 ~Kleisli[A10, T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
TraverseParTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func TraverseParTuple2 ¶
func TraverseParTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
TraverseParTuple2 converts a [tuple.Tuple2[A1, A2]] into a [IO[tuple.Tuple2[T1, T2]]]
func TraverseParTuple3 ¶
func TraverseParTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
TraverseParTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func TraverseParTuple4 ¶
func TraverseParTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
TraverseParTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func TraverseParTuple5 ¶
func TraverseParTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
TraverseParTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func TraverseParTuple6 ¶
func TraverseParTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
TraverseParTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func TraverseParTuple7 ¶
func TraverseParTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
TraverseParTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func TraverseParTuple8 ¶
func TraverseParTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
TraverseParTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func TraverseParTuple9 ¶
func TraverseParTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
TraverseParTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func TraverseSeqTuple10 ¶
func TraverseSeqTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], F10 ~Kleisli[A10, T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
TraverseSeqTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func TraverseSeqTuple2 ¶
func TraverseSeqTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
TraverseSeqTuple2 converts a [tuple.Tuple2[A1, A2]] into a [IO[tuple.Tuple2[T1, T2]]]
func TraverseSeqTuple3 ¶
func TraverseSeqTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
TraverseSeqTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func TraverseSeqTuple4 ¶
func TraverseSeqTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
TraverseSeqTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func TraverseSeqTuple5 ¶
func TraverseSeqTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
TraverseSeqTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func TraverseSeqTuple6 ¶
func TraverseSeqTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
TraverseSeqTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func TraverseSeqTuple7 ¶
func TraverseSeqTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
TraverseSeqTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func TraverseSeqTuple8 ¶
func TraverseSeqTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
TraverseSeqTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func TraverseSeqTuple9 ¶
func TraverseSeqTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
TraverseSeqTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func TraverseTuple10 ¶
func TraverseTuple10[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], F10 ~Kleisli[A10, T10], T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, A1, A2, A3, A4, A5, A6, A7, A8, A9, A10 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9, f10 F10) func(tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
TraverseTuple10 converts a [tuple.Tuple10[A1, A2, A3, A4, A5, A6, A7, A8, A9, A10]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func TraverseTuple2 ¶
func TraverseTuple2[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], T1, T2, A1, A2 any](f1 F1, f2 F2) func(tuple.Tuple2[A1, A2]) IO[tuple.Tuple2[T1, T2]]
TraverseTuple2 converts a [tuple.Tuple2[A1, A2]] into a [IO[tuple.Tuple2[T1, T2]]]
func TraverseTuple3 ¶
func TraverseTuple3[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], T1, T2, T3, A1, A2, A3 any](f1 F1, f2 F2, f3 F3) func(tuple.Tuple3[A1, A2, A3]) IO[tuple.Tuple3[T1, T2, T3]]
TraverseTuple3 converts a [tuple.Tuple3[A1, A2, A3]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func TraverseTuple4 ¶
func TraverseTuple4[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], T1, T2, T3, T4, A1, A2, A3, A4 any](f1 F1, f2 F2, f3 F3, f4 F4) func(tuple.Tuple4[A1, A2, A3, A4]) IO[tuple.Tuple4[T1, T2, T3, T4]]
TraverseTuple4 converts a [tuple.Tuple4[A1, A2, A3, A4]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func TraverseTuple5 ¶
func TraverseTuple5[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], T1, T2, T3, T4, T5, A1, A2, A3, A4, A5 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5) func(tuple.Tuple5[A1, A2, A3, A4, A5]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
TraverseTuple5 converts a [tuple.Tuple5[A1, A2, A3, A4, A5]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func TraverseTuple6 ¶
func TraverseTuple6[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], T1, T2, T3, T4, T5, T6, A1, A2, A3, A4, A5, A6 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6) func(tuple.Tuple6[A1, A2, A3, A4, A5, A6]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
TraverseTuple6 converts a [tuple.Tuple6[A1, A2, A3, A4, A5, A6]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func TraverseTuple7 ¶
func TraverseTuple7[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], T1, T2, T3, T4, T5, T6, T7, A1, A2, A3, A4, A5, A6, A7 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7) func(tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
TraverseTuple7 converts a [tuple.Tuple7[A1, A2, A3, A4, A5, A6, A7]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func TraverseTuple8 ¶
func TraverseTuple8[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], T1, T2, T3, T4, T5, T6, T7, T8, A1, A2, A3, A4, A5, A6, A7, A8 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8) func(tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
TraverseTuple8 converts a [tuple.Tuple8[A1, A2, A3, A4, A5, A6, A7, A8]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func TraverseTuple9 ¶
func TraverseTuple9[F1 ~Kleisli[A1, T1], F2 ~Kleisli[A2, T2], F3 ~Kleisli[A3, T3], F4 ~Kleisli[A4, T4], F5 ~Kleisli[A5, T5], F6 ~Kleisli[A6, T6], F7 ~Kleisli[A7, T7], F8 ~Kleisli[A8, T8], F9 ~Kleisli[A9, T9], T1, T2, T3, T4, T5, T6, T7, T8, T9, A1, A2, A3, A4, A5, A6, A7, A8, A9 any](f1 F1, f2 F2, f3 F3, f4 F4, f5 F5, f6 F6, f7 F7, f8 F8, f9 F9) func(tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
TraverseTuple9 converts a [tuple.Tuple9[A1, A2, A3, A4, A5, A6, A7, A8, A9]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func WithLock ¶
WithLock executes the provided IO operation in the scope of a lock. The lock parameter should be an IO that acquires a lock and returns a function to release it.
This ensures that the operation is executed with exclusive access to a shared resource, and the lock is always released even if the operation panics.
Example:
mutex := &sync.Mutex{}
lock := io.FromImpure(func() context.CancelFunc {
mutex.Lock()
return func() { mutex.Unlock() }
})
safeOperation := io.WithLock(lock)(dangerousOperation)
result := safeOperation()
Types ¶
type IO ¶
type IO[A any] = func() A
IO represents a synchronous computation that cannot fail. It's a function that takes no arguments and returns a value of type A. Refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioltagt] for more details.
Now is an IO computation that returns the current timestamp when executed. Each execution returns the current time at that moment.
Example:
timestamp := io.Now()
func Bracket ¶
Bracket makes sure that a resource is cleaned up in the event of an error. The release action is called regardless of whether the body action returns and error or not.
func Defer ¶
Defer creates an IO by creating a brand new IO via a generator function each time. This allows for dynamic creation of IO computations based on runtime conditions.
Example:
deferred := io.Defer(func() io.IO[int] {
if someCondition() {
return io.Of(1)
}
return io.Of(2)
})
func Do ¶
Do creates an empty context of type S to be used with the Bind operation. This is the starting point for do-notation style composition.
Example:
type State struct {
user User
posts []Post
}
result := pipe.Pipe2(
io.Do(State{}),
io.Bind("user", fetchUser),
io.Bind("posts", func(s State) io.IO[[]Post] {
return fetchPosts(s.user.Id)
}),
)
func Flatten ¶
Flatten removes one level of nesting from a nested IO computation. Converts IO[IO[A]] to IO[A].
Example:
nested := io.Of(io.Of(42)) flattened := io.Flatten(nested) result := flattened() // returns 42
func FromIO ¶
FromIO is an identity function that returns the IO value unchanged. Useful for type conversions and maintaining consistency with other monad packages.
func FromImpure ¶
FromImpure converts a side effect without a return value into a side effect that returns any
func MonadAp ¶
MonadAp implements the `ap` operation. Depending on a feature flag this will be sequential or parallel, the preferred implementation is parallel
func MonadApFirst ¶
MonadApFirst combines two effectful actions, keeping only the result of the first.
func MonadApPar ¶
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 MonadApSecond ¶
MonadApSecond combines two effectful actions, keeping only the result of the second.
func MonadApSeq ¶
MonadApSeq implements the applicative on a single thread by first executing mab and the ma
func MonadChain ¶
MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.
func MonadChainFirst ¶
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 MonadChainTo ¶
MonadChainTo composes computations in sequence, ignoring the return value of the first computation
func MonadFlap ¶
MonadFlap applies a value to a function wrapped in IO. This is the reverse of Ap - instead of applying IO[func] to IO[value], it applies a pure value to IO[func].
Example:
addFive := io.Of(N.Add(5)) result := io.MonadFlap(addFive, 10) // returns IO[15]
func MonadMap ¶
MonadMap transforms the result of an IO computation by applying a function to it. The function is only applied when the IO is executed.
Example:
doubled := io.MonadMap(io.Of(21), N.Mul(2)) result := doubled() // returns 42
func MonadMapTo ¶
MonadMapTo replaces the result of an IO computation with a constant value. The original computation is still executed, but its result is discarded.
Example:
always42 := io.MonadMapTo(sideEffect, 42)
func MonadOf ¶
MonadOf wraps a pure value in an IO context. This is an alias for Of, following the monadic naming convention.
func MonadTraverseArray ¶
MonadTraverseArray applies an IO-returning function to each element of an array and collects the results into an IO of an array. Executes in parallel by default.
Example:
fetchUsers := func(id int) io.IO[User] { return fetchUser(id) }
users := io.MonadTraverseArray([]int{1, 2, 3}, fetchUsers)
result := users() // []User with all fetched users
func MonadTraverseArraySeq ¶
MonadTraverseArraySeq applies an IO-returning function to each element of an array and collects the results into an IO of an array. Executes sequentially (one after another).
Example:
fetchUsers := func(id int) io.IO[User] { return fetchUser(id) }
users := io.MonadTraverseArraySeq([]int{1, 2, 3}, fetchUsers)
func MonadTraverseRecord ¶
func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f Kleisli[A, B]) IO[map[K]B]
MonadTraverseRecord applies an IO-returning function to each value in a map and collects the results into an IO of a map. Executes in parallel by default.
Example:
fetchData := func(url string) io.IO[Data] { return fetch(url) }
urls := map[string]string{"a": "http://a.com", "b": "http://b.com"}
data := io.MonadTraverseRecord(urls, fetchData)
func MonadTraverseRecordSeq ¶
func MonadTraverseRecordSeq[K comparable, A, B any](tas map[K]A, f Kleisli[A, B]) IO[map[K]B]
MonadTraverseRecordSeq applies an IO-returning function to each value in a map and collects the results into an IO of a map. Executes sequentially.
func Of ¶
Of wraps a pure value in an IO context, creating a computation that returns that value. This is the monadic return operation for IO.
Example:
greeting := io.Of("Hello, World!")
result := greeting() // returns "Hello, World!"
func Retrying ¶
func Retrying[A any]( policy R.RetryPolicy, action Kleisli[R.RetryStatus, A], check Predicate[A], ) IO[A]
Retrying retries an IO action according to a retry policy until it succeeds or the policy gives up.
This function implements retry logic for IO computations that don't raise exceptions but signal failure through their result value. The retry behavior is controlled by three parameters:
Parameters:
- policy: A RetryPolicy that determines the delay between retries and when to stop. Policies can be combined using the retry.Monoid to create complex retry strategies.
- action: A Kleisli arrow (function) that takes the current RetryStatus and returns an IO[A]. The action is executed on each attempt, receiving updated status information including the iteration number, cumulative delay, and previous delay.
- check: A predicate function that examines the result of the action and returns true if the operation should be retried, or false if it succeeded. This allows you to define custom success criteria based on the result value.
The function will:
- Execute the action with the current retry status
- Apply the check predicate to the result
- If check returns false (success), return the result
- If check returns true (should retry), apply the policy to get the next delay
- If the policy returns None, stop retrying and return the last result
- If the policy returns Some(delay), wait for that duration and retry from step 1
The action receives RetryStatus information on each attempt, which includes:
- IterNumber: The current attempt number (0-indexed, so 0 is the first attempt)
- CumulativeDelay: The total time spent waiting between retries so far
- PreviousDelay: The delay from the last retry (None on the first attempt)
This information can be used for logging, implementing custom backoff strategies, or making decisions within the action itself.
Example - Retry HTTP request with exponential backoff:
policy := retry.Monoid.Concat(
retry.LimitRetries(5),
retry.ExponentialBackoff(100 * time.Millisecond),
)
result := io.Retrying(
policy,
func(status retry.RetryStatus) io.IO[*http.Response] {
log.Printf("Attempt %d (cumulative delay: %v)", status.IterNumber, status.CumulativeDelay)
return io.Of(http.Get("https://api.example.com/data"))
},
func(resp *http.Response) bool {
// Retry on server errors (5xx status codes)
return resp.StatusCode >= 500
},
)
Example - Retry until a condition is met:
policy := retry.Monoid.Concat(
retry.LimitRetries(10),
retry.ConstantDelay(500 * time.Millisecond),
)
result := io.Retrying(
policy,
func(status retry.RetryStatus) io.IO[string] {
return fetchStatus()
},
func(status string) bool {
// Retry until status is "ready"
return status != "ready"
},
)
func SequenceArray ¶
SequenceArray converts an array of IO computations into an IO of an array of results. All computations are executed in parallel by default.
Example:
operations := []io.IO[int]{fetchA(), fetchB(), fetchC()}
results := io.SequenceArray(operations)
values := results() // []int with all results
func SequenceArraySeq ¶
SequenceArraySeq converts an array of IO computations into an IO of an array of results. All computations are executed sequentially (one after another).
func SequenceParT1 ¶
SequenceParT1 converts 1 [IO[T]] into a [IO[tuple.Tuple1[T1]]]
func SequenceParT10 ¶
func SequenceParT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], t10 IO[T10], ) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceParT10 converts 10 [IO[T]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceParT2 ¶
SequenceParT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceParT3 ¶
SequenceParT3 converts 3 [IO[T]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceParT4 ¶
func SequenceParT4[T1, T2, T3, T4 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], ) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceParT4 converts 4 [IO[T]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceParT5 ¶
func SequenceParT5[T1, T2, T3, T4, T5 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], ) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceParT5 converts 5 [IO[T]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceParT6 ¶
func SequenceParT6[T1, T2, T3, T4, T5, T6 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], ) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceParT6 converts 6 [IO[T]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceParT7 ¶
func SequenceParT7[T1, T2, T3, T4, T5, T6, T7 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceParT7 converts 7 [IO[T]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceParT8 ¶
func SequenceParT8[T1, T2, T3, T4, T5, T6, T7, T8 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], ) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceParT8 converts 8 [IO[T]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceParT9 ¶
func SequenceParT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], ) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceParT9 converts 9 [IO[T]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceParTuple1 ¶
SequenceParTuple1 converts a [tuple.Tuple1[IO[T]]] into a [IO[tuple.Tuple1[T1]]]
func SequenceParTuple10 ¶
func SequenceParTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9], IO[T10]]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceParTuple10 converts a [tuple.Tuple10[IO[T]]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceParTuple2 ¶
SequenceParTuple2 converts a [tuple.Tuple2[IO[T]]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceParTuple3 ¶
func SequenceParTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
SequenceParTuple3 converts a [tuple.Tuple3[IO[T]]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceParTuple4 ¶
func SequenceParTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceParTuple4 converts a [tuple.Tuple4[IO[T]]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceParTuple5 ¶
func SequenceParTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceParTuple5 converts a [tuple.Tuple5[IO[T]]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceParTuple6 ¶
func SequenceParTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceParTuple6 converts a [tuple.Tuple6[IO[T]]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceParTuple7 ¶
func SequenceParTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceParTuple7 converts a [tuple.Tuple7[IO[T]]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceParTuple8 ¶
func SequenceParTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceParTuple8 converts a [tuple.Tuple8[IO[T]]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceParTuple9 ¶
func SequenceParTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9]]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceParTuple9 converts a [tuple.Tuple9[IO[T]]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceRecord ¶
func SequenceRecord[K comparable, A any](tas map[K]IO[A]) IO[map[K]A]
SequenceRecord converts a map of IO computations into an IO of a map of results. All computations are executed in parallel by default.
Example:
operations := map[string]io.IO[int]{"a": fetchA(), "b": fetchB()}
results := io.SequenceRecord(operations)
values := results() // map[string]int with all results
func SequenceRecordSeq ¶
func SequenceRecordSeq[K comparable, A any](tas map[K]IO[A]) IO[map[K]A]
SequenceRecordSeq converts a map of IO computations into an IO of a map of results. All computations are executed sequentially (one after another).
func SequenceSeqT1 ¶
SequenceSeqT1 converts 1 [IO[T]] into a [IO[tuple.Tuple1[T1]]]
func SequenceSeqT10 ¶
func SequenceSeqT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], t10 IO[T10], ) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceSeqT10 converts 10 [IO[T]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceSeqT2 ¶
SequenceSeqT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceSeqT3 ¶
SequenceSeqT3 converts 3 [IO[T]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceSeqT4 ¶
func SequenceSeqT4[T1, T2, T3, T4 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], ) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceSeqT4 converts 4 [IO[T]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceSeqT5 ¶
func SequenceSeqT5[T1, T2, T3, T4, T5 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], ) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceSeqT5 converts 5 [IO[T]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceSeqT6 ¶
func SequenceSeqT6[T1, T2, T3, T4, T5, T6 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], ) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceSeqT6 converts 6 [IO[T]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceSeqT7 ¶
func SequenceSeqT7[T1, T2, T3, T4, T5, T6, T7 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceSeqT7 converts 7 [IO[T]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceSeqT8 ¶
func SequenceSeqT8[T1, T2, T3, T4, T5, T6, T7, T8 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], ) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceSeqT8 converts 8 [IO[T]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceSeqT9 ¶
func SequenceSeqT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], ) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceSeqT9 converts 9 [IO[T]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceSeqTuple1 ¶
SequenceSeqTuple1 converts a [tuple.Tuple1[IO[T]]] into a [IO[tuple.Tuple1[T1]]]
func SequenceSeqTuple10 ¶
func SequenceSeqTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9], IO[T10]]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceSeqTuple10 converts a [tuple.Tuple10[IO[T]]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceSeqTuple2 ¶
SequenceSeqTuple2 converts a [tuple.Tuple2[IO[T]]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceSeqTuple3 ¶
func SequenceSeqTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
SequenceSeqTuple3 converts a [tuple.Tuple3[IO[T]]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceSeqTuple4 ¶
func SequenceSeqTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceSeqTuple4 converts a [tuple.Tuple4[IO[T]]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceSeqTuple5 ¶
func SequenceSeqTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceSeqTuple5 converts a [tuple.Tuple5[IO[T]]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceSeqTuple6 ¶
func SequenceSeqTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceSeqTuple6 converts a [tuple.Tuple6[IO[T]]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceSeqTuple7 ¶
func SequenceSeqTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceSeqTuple7 converts a [tuple.Tuple7[IO[T]]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceSeqTuple8 ¶
func SequenceSeqTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceSeqTuple8 converts a [tuple.Tuple8[IO[T]]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceSeqTuple9 ¶
func SequenceSeqTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9]]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceSeqTuple9 converts a [tuple.Tuple9[IO[T]]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceT1 ¶
SequenceT1 converts 1 [IO[T]] into a [IO[tuple.Tuple1[T1]]]
func SequenceT10 ¶
func SequenceT10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], t10 IO[T10], ) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceT10 converts 10 [IO[T]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceT2 ¶
SequenceT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceT3 ¶
SequenceT3 converts 3 [IO[T]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceT4 ¶
func SequenceT4[T1, T2, T3, T4 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], ) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceT4 converts 4 [IO[T]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceT5 ¶
func SequenceT5[T1, T2, T3, T4, T5 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], ) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceT5 converts 5 [IO[T]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceT6 ¶
func SequenceT6[T1, T2, T3, T4, T5, T6 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], ) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceT6 converts 6 [IO[T]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceT7 ¶
func SequenceT7[T1, T2, T3, T4, T5, T6, T7 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], ) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceT7 converts 7 [IO[T]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceT8 ¶
func SequenceT8[T1, T2, T3, T4, T5, T6, T7, T8 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], ) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceT8 converts 8 [IO[T]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceT9 ¶
func SequenceT9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any]( t1 IO[T1], t2 IO[T2], t3 IO[T3], t4 IO[T4], t5 IO[T5], t6 IO[T6], t7 IO[T7], t8 IO[T8], t9 IO[T9], ) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceT9 converts 9 [IO[T]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func SequenceTuple1 ¶
SequenceTuple1 converts a [tuple.Tuple1[IO[T]]] into a [IO[tuple.Tuple1[T1]]]
func SequenceTuple10 ¶
func SequenceTuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10 any](t tuple.Tuple10[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9], IO[T10]]) IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]
SequenceTuple10 converts a [tuple.Tuple10[IO[T]]] into a [IO[tuple.Tuple10[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]]]
func SequenceTuple2 ¶
SequenceTuple2 converts a [tuple.Tuple2[IO[T]]] into a [IO[tuple.Tuple2[T1, T2]]]
func SequenceTuple3 ¶
func SequenceTuple3[T1, T2, T3 any](t tuple.Tuple3[IO[T1], IO[T2], IO[T3]]) IO[tuple.Tuple3[T1, T2, T3]]
SequenceTuple3 converts a [tuple.Tuple3[IO[T]]] into a [IO[tuple.Tuple3[T1, T2, T3]]]
func SequenceTuple4 ¶
func SequenceTuple4[T1, T2, T3, T4 any](t tuple.Tuple4[IO[T1], IO[T2], IO[T3], IO[T4]]) IO[tuple.Tuple4[T1, T2, T3, T4]]
SequenceTuple4 converts a [tuple.Tuple4[IO[T]]] into a [IO[tuple.Tuple4[T1, T2, T3, T4]]]
func SequenceTuple5 ¶
func SequenceTuple5[T1, T2, T3, T4, T5 any](t tuple.Tuple5[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5]]) IO[tuple.Tuple5[T1, T2, T3, T4, T5]]
SequenceTuple5 converts a [tuple.Tuple5[IO[T]]] into a [IO[tuple.Tuple5[T1, T2, T3, T4, T5]]]
func SequenceTuple6 ¶
func SequenceTuple6[T1, T2, T3, T4, T5, T6 any](t tuple.Tuple6[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6]]) IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]
SequenceTuple6 converts a [tuple.Tuple6[IO[T]]] into a [IO[tuple.Tuple6[T1, T2, T3, T4, T5, T6]]]
func SequenceTuple7 ¶
func SequenceTuple7[T1, T2, T3, T4, T5, T6, T7 any](t tuple.Tuple7[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7]]) IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]
SequenceTuple7 converts a [tuple.Tuple7[IO[T]]] into a [IO[tuple.Tuple7[T1, T2, T3, T4, T5, T6, T7]]]
func SequenceTuple8 ¶
func SequenceTuple8[T1, T2, T3, T4, T5, T6, T7, T8 any](t tuple.Tuple8[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8]]) IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]
SequenceTuple8 converts a [tuple.Tuple8[IO[T]]] into a [IO[tuple.Tuple8[T1, T2, T3, T4, T5, T6, T7, T8]]]
func SequenceTuple9 ¶
func SequenceTuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9 any](t tuple.Tuple9[IO[T1], IO[T2], IO[T3], IO[T4], IO[T5], IO[T6], IO[T7], IO[T8], IO[T9]]) IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]
SequenceTuple9 converts a [tuple.Tuple9[IO[T]]] into a [IO[tuple.Tuple9[T1, T2, T3, T4, T5, T6, T7, T8, T9]]]
func WithDuration ¶
WithDuration returns an IO that measures the execution time.Duration of the operation. Returns a Pair with the duration as the head and the result as the tail. The result is placed in the tail position because that is the value that the pair monad operates on, allowing monadic operations to transform the result while preserving the duration.
Example:
timed := io.WithDuration(expensiveComputation)
p := timed()
duration := pair.Head(p)
result := pair.Tail(p)
fmt.Printf("Took %v\n", duration)
func WithTime ¶
WithTime returns an IO that measures the start and end time.Time of the operation. Returns a Pair[Pair[time.Time, time.Time], A] where the head contains a nested pair of (start time, end time) and the tail contains the result. The result is placed in the tail position because that is the value that the pair monad operates on, allowing monadic operations to transform the result while preserving the timing information.
Example:
timed := io.WithTime(expensiveComputation) p := timed() times := pair.Head(p) // Pair[time.Time, time.Time] result := pair.Tail(p) // A start := pair.Head(times) // time.Time end := pair.Tail(times) // time.Time
type IOApplicative ¶
type IOApplicative[A, B any] = applicative.Applicative[A, B, IO[A], IO[B], IO[func(A) B]]
IOApplicative represents the applicative functor type class for IO. It combines the capabilities of Functor (Map) and Pointed (Of) with the ability to apply wrapped functions to wrapped values (Ap).
func Applicative ¶
func Applicative[A, B any]() IOApplicative[A, B]
Applicative returns an instance of the Applicative type class for IO. This provides a structured way to access applicative operations (Of, Map, Ap) for IO computations.
Example:
app := io.Applicative[int, string]() result := app.Map(strconv.Itoa)(app.Of(42))
type IOFunctor ¶
IOFunctor represents the functor type class for IO. A functor allows mapping a function over a wrapped value without unwrapping it, preserving the structure.
type IOMonad ¶
IOMonad represents the monad type class for IO. A monad combines the capabilities of Functor, Applicative, and Pointed with the ability to chain computations (Chain/FlatMap).
func Monad ¶
func Monad[A, B any]() IOMonad[A, B]
Monad returns an instance of the Monad type class for IO. This provides a structured way to access monadic operations (Of, Map, Chain, Ap) for IO computations.
Example:
m := io.Monad[int, string]()
result := m.Chain(func(n int) io.IO[string] {
return io.Of(strconv.Itoa(n))
})(m.Of(42))
type IOPointed ¶
IOPointed represents the pointed functor type class for IO. A pointed functor is a functor with the ability to lift a pure value into the functor context (Of operation).
type Kleisli ¶
Kleisli represents a Kleisli arrow for the IO monad. It's a function from A to IO[B], used for composing IO operations.
func FromConsumer ¶ added in v2.1.1
func FromConsumer[A any](c Consumer[A]) Kleisli[A, Void]
FromConsumer converts a Consumer into a Kleisli arrow that wraps the consumer in an IO context.
This function lifts a Consumer[A] (a function that consumes a value and performs side effects) into a Kleisli[A, struct{}] (a function that takes a value and returns an IO computation that performs the side effect and returns an empty struct).
The resulting Kleisli arrow can be used with Chain and other monadic operations to integrate consumers into IO pipelines. This is a lower-level function compared to ChainConsumer, which directly returns an Operator.
Type Parameters:
- A: The type of value consumed by the consumer
Parameters:
- c: A Consumer[A] that performs side effects on values of type A
Returns:
- A Kleisli[A, struct{}] that wraps the consumer in an IO context
Example:
// Create a consumer
logger := func(x int) {
fmt.Printf("Logging: %d\n", x)
}
// Convert to Kleisli arrow
logKleisli := io.FromConsumer(logger)
// Use with Chain
result := F.Pipe2(
io.Of(42),
io.Chain(logKleisli), // Logs "Logging: 42"
io.Map(func(struct{}) string { return "completed" }),
)
result() // Returns "completed"
// Can also be used to build more complex operations
logAndCount := func(x int) io.IO[int] {
return F.Pipe2(
logKleisli(x),
io.Map(func(struct{}) int { return 1 }),
)
}
func LogGo ¶
LogGo constructs a logger function using Go template syntax for formatting. The prefix string is parsed as a Go template and executed with the value as data. Both successful output and template errors are logged using log.Println.
Example:
type User struct {
Name string
Age int
}
result := pipe.Pipe2(
fetchUser(),
io.ChainFirst(io.LogGo[User]("User: {{.Name}}, Age: {{.Age}}")),
processUser,
)
func Logf ¶
Logf constructs a logger function that can be used with ChainFirst or similar operations. The prefix string contains the format string for the log value.
Example:
result := pipe.Pipe2(
fetchUser(),
io.ChainFirst(io.Logf[User]("User: %+v")),
processUser,
)
func PrintGo ¶
PrintGo constructs a printer function using Go template syntax for formatting. The prefix string is parsed as a Go template and executed with the value as data. Successful output is printed to stdout using fmt.Println, while template errors are printed to stderr using fmt.Fprintln.
Example:
type User struct {
Name string
Age int
}
result := pipe.Pipe2(
fetchUser(),
io.ChainFirst(io.PrintGo[User]("User: {{.Name}}, Age: {{.Age}}")),
processUser,
)
func Printf ¶
Printf constructs a printer function that can be used with ChainFirst or similar operations. The prefix string contains the format string for the printed value. Unlike Logf, this prints to stdout without log prefixes.
Example:
result := pipe.Pipe2(
fetchUser(),
io.ChainFirst(io.Printf[User]("User: %+v\n")),
processUser,
)
func TailRec ¶ added in v2.1.0
func TailRec[A, B any](f Kleisli[A, Trampoline[A, B]]) Kleisli[A, B]
TailRec creates a tail-recursive computation in the IO monad. It enables writing recursive algorithms that don't overflow the call stack by using trampolining - a technique where recursive calls are converted into iterations.
The function takes a step function that returns a Trampoline:
- Bounce(A): Continue recursion with a new value of type A
- Land(B): Terminate recursion with a final result of type B
This is particularly useful for implementing recursive algorithms like:
- Iterative calculations (factorial, fibonacci, sum, etc.)
- State machines with multiple steps
- Loops over large data structures
- Processing collections with complex iteration logic
The recursion is stack-safe because each step returns a value that indicates whether to continue (Bounce) or stop (Land), rather than making direct recursive calls. This allows processing arbitrarily large inputs without stack overflow.
Type Parameters:
- A: The intermediate type used during recursion (loop state)
- B: The final result type when recursion terminates
Parameters:
- f: A step function that takes the current state (A) and returns an IO containing either Bounce(A) to continue with a new state, or Land(B) to terminate with a final result
Returns:
- A Kleisli arrow (function from A to IO[B]) that executes the tail-recursive computation starting from the initial value
Example - Computing factorial in a stack-safe way:
type FactState struct {
n int
result int
}
factorial := io.TailRec(func(state FactState) io.IO[tailrec.Trampoline[FactState, int]] {
if state.n <= 1 {
// Terminate with final result
return io.Of(tailrec.Land[FactState](state.result))
}
// Continue with next iteration
return io.Of(tailrec.Bounce[int](FactState{
n: state.n - 1,
result: state.result * state.n,
}))
})
result := factorial(FactState{n: 5, result: 1})() // 120
Example - Sum of numbers from 1 to N:
type SumState struct {
current int
limit int
sum int
}
sumToN := io.TailRec(func(state SumState) io.IO[tailrec.Trampoline[SumState, int]] {
if state.current > state.limit {
return io.Of(tailrec.Land[SumState](state.sum))
}
return io.Of(tailrec.Bounce[int](SumState{
current: state.current + 1,
limit: state.limit,
sum: state.sum + state.current,
}))
})
result := sumToN(SumState{current: 1, limit: 100, sum: 0})() // 5050
Example - Processing a list with accumulation:
type ListState struct {
items []int
acc []int
}
doubleAll := io.TailRec(func(state ListState) io.IO[tailrec.Trampoline[ListState, []int]] {
if len(state.items) == 0 {
return io.Of(tailrec.Land[ListState](state.acc))
}
doubled := append(state.acc, state.items[0]*2)
return io.Of(tailrec.Bounce[[]int](ListState{
items: state.items[1:],
acc: doubled,
}))
})
result := doubleAll(ListState{items: []int{1, 2, 3}, acc: []int{}})() // [2, 4, 6]
Example - Fibonacci sequence:
type FibState struct {
n int
prev int
curr int
}
fibonacci := io.TailRec(func(state FibState) io.IO[tailrec.Trampoline[FibState, int]] {
if state.n == 0 {
return io.Of(tailrec.Land[FibState](state.curr))
}
return io.Of(tailrec.Bounce[int](FibState{
n: state.n - 1,
prev: state.curr,
curr: state.prev + state.curr,
}))
})
result := fibonacci(FibState{n: 10, prev: 0, curr: 1})() // 55
func TraverseArray ¶
func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]
TraverseArray returns a function that applies an IO-returning function to each element of an array and collects the results. This is the curried version of MonadTraverseArray. Executes in parallel by default.
Example:
fetchUsers := io.TraverseArray(func(id int) io.IO[User] {
return fetchUser(id)
})
users := fetchUsers([]int{1, 2, 3})
func TraverseArraySeq ¶
func TraverseArraySeq[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]
TraverseArraySeq returns a function that applies an IO-returning function to each element of an array and collects the results. Executes sequentially (one after another). Use this when operations must be performed in order or when parallel execution is not desired.
func TraverseArrayWithIndex ¶
TraverseArrayWithIndex is like TraverseArray but the function also receives the index. Executes in parallel by default.
Example:
numbered := io.TraverseArrayWithIndex(func(i int, s string) io.IO[string] {
return io.Of(fmt.Sprintf("%d: %s", i, s))
})
func TraverseArrayWithIndexSeq ¶
TraverseArrayWithIndexSeq is like TraverseArraySeq but the function also receives the index. Executes sequentially (one after another).
func TraverseIter ¶
func TraverseIter[A, B any](f Kleisli[A, B]) Kleisli[Seq[A], Seq[B]]
func TraverseParTuple1 ¶
func TraverseParTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
TraverseParTuple1 converts a [tuple.Tuple1[A1]] into a [IO[tuple.Tuple1[T1]]]
func TraverseRecord ¶
func TraverseRecord[K comparable, A, B any](f Kleisli[A, B]) Kleisli[map[K]A, map[K]B]
TraverseRecord returns a function that applies an IO-returning function to each value in a map and collects the results. This is the curried version of MonadTraverseRecord. Executes in parallel by default.
func TraverseRecordSeq ¶
func TraverseRecordSeq[K comparable, A, B any](f Kleisli[A, B]) Kleisli[map[K]A, map[K]B]
TraverseRecordSeq returns a function that applies an IO-returning function to each value in a map and collects the results. Executes sequentially (one after another).
func TraverseRecordWithIndeSeq ¶
func TraverseRecordWithIndeSeq[K comparable, A, B any](f func(K, A) IO[B]) Kleisli[map[K]A, map[K]B]
TraverseRecordWithIndeSeq is like TraverseRecordSeq but the function also receives the key. Executes sequentially (one after another). Note: There's a typo in the function name (Inde instead of Index) for backward compatibility.
func TraverseRecordWithIndex ¶
func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) IO[B]) Kleisli[map[K]A, map[K]B]
TraverseRecordWithIndex is like TraverseRecord but the function also receives the key. Executes in parallel by default.
func TraverseSeqTuple1 ¶
func TraverseSeqTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
TraverseSeqTuple1 converts a [tuple.Tuple1[A1]] into a [IO[tuple.Tuple1[T1]]]
func TraverseTuple1 ¶
func TraverseTuple1[F1 ~Kleisli[A1, T1], T1, A1 any](f1 F1) Kleisli[tuple.Tuple1[A1], tuple.Tuple1[T1]]
TraverseTuple1 converts a [tuple.Tuple1[A1]] into a [IO[tuple.Tuple1[T1]]]
func WithResource ¶
func WithResource[ R, A, ANY any](onCreate IO[R], onRelease func(R) IO[ANY]) Kleisli[Kleisli[R, A], A]
WithResource constructs a function that creates a resource, operates on it, and then releases it. This is a higher-level abstraction over Bracket that simplifies resource management patterns.
The resource is guaranteed to be released even if the operation fails or panics.
Example:
withFile := io.WithResource(
io.Of(openFile("data.txt")),
func(f *os.File) io.IO[any] {
return io.FromImpure(func() { f.Close() })
},
)
result := withFile(func(f *os.File) io.IO[Data] {
return readData(f)
})
type Monoid ¶
Monoid represents a monoid structure for IO values.
func ApplicativeMonoid ¶
ApplicativeMonoid lifts a Monoid[A] into a Monoid[IO[A]]. This allows combining IO computations using the monoid operation on their results, including an empty/identity element.
Example:
intAdd := monoid.MakeMonoid(func(a, b int) int { return a + b }, 0)
ioAdd := io.ApplicativeMonoid(intAdd)
result := ioAdd.Concat(io.Of(1), io.Of(2)) // IO[3]
empty := ioAdd.Empty() // IO[0]
type Operator ¶
Operator represents a function that transforms one IO into another. It takes an IO[A] and produces an IO[B].
func After ¶
After creates an operator that delays execution until after the given timestamp. If the timestamp is in the past, the computation executes immediately.
Example:
future := time.Now().Add(5 * time.Second) scheduled := io.After(future)(io.Of(42)) result := scheduled() // waits until future time, then returns 42
func Ap ¶
Ap returns an operator that applies a function wrapped in IO to a value wrapped in IO. This is the curried version of MonadAp and uses parallel execution by default.
Example:
add := func(a int) func(int) int { return func(b int) int { return a + b } }
result := io.Ap(io.Of(2))(io.Of(add(3))) // parallel execution
func ApPar ¶
ApPar returns an operator that applies a function wrapped in IO to a value wrapped in IO in parallel. This explicitly uses parallel execution (same as Ap when useParallel is true).
func ApS ¶
ApS attaches a value to a context S1 to produce a context S2 by considering the context and the value concurrently (using applicative operations). This allows parallel execution of independent computations.
Example:
io.ApS(func(posts []Post) func(s State) State {
return func(s State) State {
s.posts = posts
return s
}
}, fetchPosts())
func ApSL ¶
ApSL attaches a value to a context using a lens-based setter. This is a convenience function that combines ApS with a lens, allowing you to use optics to update nested structures in a more composable way.
The lens parameter provides both the getter and setter for a field within the structure S. This eliminates the need to manually write setter functions.
Example:
type Config struct {
Host string
Port int
}
portLens := lens.MakeLens(
func(c Config) int { return c.Port },
func(c Config, p int) Config { c.Port = p; return c },
)
result := F.Pipe2(
io.Of(Config{Host: "localhost"}),
io.ApSL(portLens, io.Of(8080)),
)
func ApSeq ¶
ApSeq returns an operator that applies a function wrapped in IO to a value wrapped in IO sequentially. Unlike Ap, this executes the function and value computations in sequence.
func Bind ¶
func Bind[S1, S2, T any]( setter func(T) func(S1) S2, f Kleisli[S1, T], ) Operator[S1, S2]
Bind attaches the result of an IO computation to a context S1 to produce a context S2. This is used in do-notation style composition to build up state incrementally.
The setter function takes the result T and returns a function that updates S1 to S2.
Example:
io.Bind(func(user User) func(s State) State {
return func(s State) State {
s.user = user
return s
}
}, fetchUser)
func BindL ¶
BindL attaches the result of a computation to a context using a lens-based setter. This is a convenience function that combines Bind with a lens, allowing you to use optics to update nested structures based on their current values.
The lens parameter provides both the getter and setter for a field within the structure S. The computation function f receives the current value of the focused field and returns an IO that produces the new value.
Example:
type Counter struct {
Value int
}
valueLens := lens.MakeLens(
func(c Counter) int { return c.Value },
func(c Counter, v int) Counter { c.Value = v; return c },
)
// Increment the counter asynchronously
increment := func(v int) io.IO[int] {
return io.Of(v + 1)
}
result := F.Pipe1(
io.Of(Counter{Value: 42}),
io.BindL(valueLens, increment),
) // IO[Counter{Value: 43}]
func BindTo ¶
func BindTo[S1, T any]( setter func(T) S1, ) Operator[T, S1]
BindTo initializes a new state S1 from a value T. This is typically used to start a do-notation chain from a single value.
Example:
io.BindTo(func(user User) State {
return State{user: user}
})
func Chain ¶
func Chain[A, B any](f Kleisli[A, B]) Operator[A, B]
Chain composes computations in sequence, using the return value of one computation to determine the next computation.
func ChainConsumer ¶
func ChainConsumer[A any](c Consumer[A]) Operator[A, Void]
ChainConsumer converts a Consumer into an IO operator that executes the consumer as a side effect and returns an empty struct.
This function bridges the gap between pure consumers (functions that consume values without returning anything) and the IO monad. It takes a Consumer[A] and returns an Operator that:
- Executes the source IO[A] to get a value
- Passes that value to the consumer for side effects
- Returns IO[struct{}] to maintain the monadic chain
The returned IO[struct{}] allows the operation to be composed with other IO operations while discarding the consumed value. This is useful for operations like logging, printing, or updating external state within an IO pipeline.
Type Parameters:
- A: The type of value consumed by the consumer
Parameters:
- c: A Consumer[A] that performs side effects on values of type A
Returns:
- An Operator[A, struct{}] that executes the consumer and returns an empty struct
Example:
// Create a consumer that logs values
logger := func(x int) {
fmt.Printf("Value: %d\n", x)
}
// Convert it to an IO operator
logOp := io.ChainConsumer(logger)
// Use it in an IO pipeline
result := F.Pipe2(
io.Of(42),
logOp, // Logs "Value: 42"
io.Map(func(struct{}) string { return "done" }),
)
result() // Returns "done" after logging
// Another example with multiple operations
var values []int
collector := func(x int) {
values = append(values, x)
}
pipeline := F.Pipe2(
io.Of(100),
io.ChainConsumer(collector), // Collects the value
io.Map(func(struct{}) int { return len(values) }),
)
count := pipeline() // Returns 1, values contains [100]
func ChainFirst ¶
func ChainFirst[A, B any](f Kleisli[A, B]) Operator[A, A]
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 ChainTo ¶
ChainTo composes computations in sequence, ignoring the return value of the first computation
func Delay ¶
Delay creates an operator that delays execution by the specified duration. The delay occurs before executing the wrapped computation.
Example:
delayed := io.Delay(time.Second)(io.Of(42)) result := delayed() // waits 1 second, then returns 42
func Flap ¶
func Flap[B, A any](a A) Operator[func(A) B, B]
Flap returns an operator that applies a pure value to a function wrapped in IO. This is the curried version of MonadFlap.
func Let ¶
func Let[S1, S2, T any]( setter func(T) func(S1) S2, f func(S1) T, ) Operator[S1, S2]
Let attaches the result of a pure computation to a context S1 to produce a context S2. Similar to Bind, but for pure (non-IO) computations.
Example:
io.Let(func(count int) func(s State) State {
return func(s State) State {
s.count = count
return s
}
}, func(s State) int { return len(s.items) })
func LetL ¶
LetL attaches the result of a pure computation to a context using a lens-based setter. This is a convenience function that combines Let with a lens, allowing you to use optics to update nested structures with pure transformations.
The lens parameter provides both the getter and setter for a field within the structure S. The transformation function f receives the current value of the focused field and returns the new value directly (not wrapped in IO).
Example:
type Counter struct {
Value int
}
valueLens := lens.MakeLens(
func(c Counter) int { return c.Value },
func(c Counter, v int) Counter { c.Value = v; return c },
)
// Double the counter value
double := func(v int) int { return v * 2 }
result := F.Pipe1(
io.Of(Counter{Value: 21}),
io.LetL(valueLens, double),
) // IO[Counter{Value: 42}]
func LetTo ¶
func LetTo[S1, S2, T any]( setter func(T) func(S1) S2, b T, ) Operator[S1, S2]
LetTo attaches a constant value to a context S1 to produce a context S2. Similar to Let, but with a constant value instead of a computation.
Example:
io.LetTo(func(status string) func(s State) State {
return func(s State) State {
s.status = status
return s
}
}, "ready")
func LetToL ¶
LetToL attaches a constant value to a context using a lens-based setter. This is a convenience function that combines LetTo with a lens, allowing you to use optics to set nested fields to specific values.
The lens parameter provides the setter for a field within the structure S. Unlike LetL which transforms the current value, LetToL simply replaces it with the provided constant value b.
Example:
type Config struct {
Debug bool
Timeout int
}
debugLens := lens.MakeLens(
func(c Config) bool { return c.Debug },
func(c Config, d bool) Config { c.Debug = d; return c },
)
result := F.Pipe1(
io.Of(Config{Debug: true, Timeout: 30}),
io.LetToL(debugLens, false),
) // IO[Config{Debug: false, Timeout: 30}]
type Predicate ¶ added in v2.1.0
Predicate represents a function that tests a value of type A and returns a boolean. It's commonly used for filtering and conditional operations.
type RetryStatus ¶
type RetryStatus = IO[R.RetryStatus]
RetryStatus is an IO computation that returns retry status information. It wraps the retry.RetryStatus type in the IO monad, allowing retry status to be computed lazily as part of an IO effect.
type Semigroup ¶
Semigroup represents a semigroup structure for IO values.
func ApplySemigroup ¶
ApplySemigroup lifts a Semigroup[A] into a Semigroup[IO[A]]. This allows combining IO computations using the semigroup operation on their results.
Example:
intAdd := semigroup.MakeSemigroup(func(a, b int) int { return a + b })
ioAdd := io.ApplySemigroup(intAdd)
result := ioAdd.Concat(io.Of(1), io.Of(2)) // IO[3]
type Trampoline ¶ added in v2.1.0
type Trampoline[B, L any] = tailrec.Trampoline[B, L]
Trampoline represents a tail-recursive computation that can be evaluated safely without stack overflow. It's used for implementing stack-safe recursive algorithms.