io

package
v2.0.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Dec 20, 2025 License: Apache-2.0 Imports: 33 Imported by: 0

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:

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

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Eq

func Eq[A any](e EQ.Eq[A]) EQ.Eq[IO[A]]

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

func Logger[A any](loggers ...*log.Logger) func(string) Kleisli[A, A]

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 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

func WithLock[A any](lock IO[context.CancelFunc]) func(fa IO[A]) IO[A]

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 Consumer

type Consumer[A any] = consumer.Consumer[A]

type IO

type IO[A any] = func() A

IO represents a synchronous computation that cannot fail refer to [https://andywhite.xyz/posts/2021-01-27-rte-foundations/#ioltagt] for more details

var Now IO[time.Time] = time.Now

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

func Bracket[A, B, ANY any](
	acquire IO[A],
	use Kleisli[A, B],
	release func(A, B) IO[ANY],
) IO[B]

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

func Defer[A any](gen func() IO[A]) IO[A]

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

func Do[S any](
	empty S,
) IO[S]

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

func Flatten[A any](mma IO[IO[A]]) IO[A]

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

func FromIO[A any](a IO[A]) IO[A]

FromIO is an identity function that returns the IO value unchanged. Useful for type conversions and maintaining consistency with other monad packages.

func FromImpure

func FromImpure[ANY ~func()](f ANY) IO[any]

FromImpure converts a side effect without a return value into a side effect that returns any

func Memoize

func Memoize[A any](ma IO[A]) IO[A]

Memoize computes the value of the provided IO monad lazily but exactly once

func MonadAp

func MonadAp[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]

MonadAp implements the `ap` operation. Depending on a feature flag this will be sequential or parallel, the preferred implementation is parallel

func MonadApFirst

func MonadApFirst[A, B any](first IO[A], second IO[B]) IO[A]

MonadApFirst combines two effectful actions, keeping only the result of the first.

func MonadApPar

func MonadApPar[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]

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

func MonadApSecond[A, B any](first IO[A], second IO[B]) IO[B]

MonadApSecond combines two effectful actions, keeping only the result of the second.

func MonadApSeq

func MonadApSeq[A, B any](mab IO[func(A) B], ma IO[A]) IO[B]

MonadApSeq implements the applicative on a single thread by first executing mab and the ma

func MonadChain

func MonadChain[A, B any](fa IO[A], f Kleisli[A, B]) IO[B]

MonadChain composes computations in sequence, using the return value of one computation to determine the next computation.

func MonadChainFirst

func MonadChainFirst[A, B any](fa IO[A], f Kleisli[A, B]) IO[A]

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

func MonadChainTo[A, B any](fa IO[A], fb IO[B]) IO[B]

MonadChainTo composes computations in sequence, ignoring the return value of the first computation

func MonadFlap

func MonadFlap[B, A any](fab IO[func(A) B], a A) IO[B]

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

func MonadMap[A, B any](fa IO[A], f func(A) B) IO[B]

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

func MonadMapTo[A, B any](fa IO[A], b B) IO[B]

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

func MonadOf[A any](a A) IO[A]

MonadOf wraps a pure value in an IO context. This is an alias for Of, following the monadic naming convention.

func MonadTraverseArray

func MonadTraverseArray[A, B any](tas []A, f Kleisli[A, B]) IO[[]B]

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

func MonadTraverseArraySeq[A, B any](tas []A, f Kleisli[A, B]) IO[[]B]

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

func Of[A any](a A) IO[A]

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 func(A) bool,
) IO[A]

Retrying retries an IO action according to a retry policy until it succeeds or the policy gives up.

Parameters:

  • policy: The retry policy that determines delays and maximum attempts
  • action: A function that takes retry status and returns an IO computation
  • check: A predicate that determines if the result should trigger a retry (true = retry)

The action receives retry status information (attempt number, cumulative delay, etc.) which can be used for logging or conditional behavior.

Example:

result := io.Retrying(
    retry.ExponentialBackoff(time.Second, 5),
    func(status retry.RetryStatus) io.IO[Response] {
        log.Printf("Attempt %d", status.IterNumber)
        return fetchData()
    },
    func(r Response) bool { return r.StatusCode >= 500 },
)

func SequenceArray

func SequenceArray[A any](tas []IO[A]) IO[[]A]

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

func SequenceArraySeq[A any](tas []IO[A]) IO[[]A]

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

func SequenceParT1[T1 any](
	t1 IO[T1],
) IO[tuple.Tuple1[T1]]

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

func SequenceParT2[T1, T2 any](
	t1 IO[T1],
	t2 IO[T2],
) IO[tuple.Tuple2[T1, T2]]

SequenceParT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]

func SequenceParT3

func SequenceParT3[T1, T2, T3 any](
	t1 IO[T1],
	t2 IO[T2],
	t3 IO[T3],
) IO[tuple.Tuple3[T1, T2, T3]]

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

func SequenceParTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]

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

func SequenceParTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]

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

func SequenceSeqT1[T1 any](
	t1 IO[T1],
) IO[tuple.Tuple1[T1]]

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

func SequenceSeqT2[T1, T2 any](
	t1 IO[T1],
	t2 IO[T2],
) IO[tuple.Tuple2[T1, T2]]

SequenceSeqT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]

func SequenceSeqT3

func SequenceSeqT3[T1, T2, T3 any](
	t1 IO[T1],
	t2 IO[T2],
	t3 IO[T3],
) IO[tuple.Tuple3[T1, T2, T3]]

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

func SequenceSeqTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]

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

func SequenceSeqTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]

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

func SequenceT1[T1 any](
	t1 IO[T1],
) IO[tuple.Tuple1[T1]]

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

func SequenceT2[T1, T2 any](
	t1 IO[T1],
	t2 IO[T2],
) IO[tuple.Tuple2[T1, T2]]

SequenceT2 converts 2 [IO[T]] into a [IO[tuple.Tuple2[T1, T2]]]

func SequenceT3

func SequenceT3[T1, T2, T3 any](
	t1 IO[T1],
	t2 IO[T2],
	t3 IO[T3],
) IO[tuple.Tuple3[T1, T2, T3]]

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

func SequenceTuple1[T1 any](t tuple.Tuple1[IO[T1]]) IO[tuple.Tuple1[T1]]

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

func SequenceTuple2[T1, T2 any](t tuple.Tuple2[IO[T1], IO[T2]]) IO[tuple.Tuple2[T1, T2]]

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

func WithDuration[A any](a IO[A]) IO[Pair[time.Duration, A]]

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

func WithTime[A any](a IO[A]) IO[Pair[Pair[time.Time, time.Time], A]]

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

type IOFunctor[A, B any] = functor.Functor[A, B, IO[A], IO[B]]

IOFunctor represents the functor type class for IO. A functor allows mapping a function over a wrapped value without unwrapping it, preserving the structure.

func Functor

func Functor[A, B any]() IOFunctor[A, B]

Functor returns an instance of the Functor type class for IO. This provides a structured way to access functor operations (Map) for IO computations.

Example:

f := io.Functor[int, string]()
result := f.Map(strconv.Itoa)(io.Of(42))

type IOMonad

type IOMonad[A, B any] = monad.Monad[A, B, IO[A], IO[B], IO[func(A) B]]

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

type IOPointed[A any] = pointed.Pointed[A, IO[A]]

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).

func Pointed

func Pointed[A any]() IOPointed[A]

Pointed returns an instance of the Pointed type class for IO. This provides a structured way to access the Of operation for IO computations.

Example:

p := io.Pointed[int]()
result := p.Of(42)

type Kleisli

type Kleisli[A, B any] = reader.Reader[A, IO[B]]

func FromConsumerK

func FromConsumerK[A any](c Consumer[A]) Kleisli[A, struct{}]

FromConsumerK 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.FromConsumerK(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

func LogGo[A any](prefix string) Kleisli[A, A]

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

func Logf[A any](prefix string) Kleisli[A, A]

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

func PrintGo[A any](prefix string) Kleisli[A, A]

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

func Printf[A any](prefix string) Kleisli[A, A]

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 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

func TraverseArrayWithIndex[A, B any](f func(int, A) IO[B]) Kleisli[[]A, []B]

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

func TraverseArrayWithIndexSeq[A, B any](f func(int, A) IO[B]) Kleisli[[]A, []B]

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

type Monoid[A any] = M.Monoid[IO[A]]

func ApplicativeMonoid

func ApplicativeMonoid[A any](m M.Monoid[A]) Monoid[A]

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

type Operator[A, B any] = Kleisli[IO[A], B]

func After

func After[A any](timestamp time.Time) Operator[A, A]

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

func Ap[B, A any](ma IO[A]) Operator[func(A) B, B]

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 ApFirst

func ApFirst[A, B any](second IO[B]) Operator[A, A]

ApFirst combines two effectful actions, keeping only the result of the first.

func ApPar

func ApPar[B, A any](ma IO[A]) Operator[func(A) B, B]

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

func ApS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa IO[T],
) Operator[S1, S2]

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

func ApSL[S, T any](
	lens L.Lens[S, T],
	fa IO[T],
) Operator[S, S]

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 ApSecond

func ApSecond[A, B any](second IO[B]) Operator[A, B]

ApSecond combines two effectful actions, keeping only the result of the second.

func ApSeq

func ApSeq[B, A any](ma IO[A]) Operator[func(A) B, B]

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

func BindL[S, T any](
	lens L.Lens[S, T],
	f Kleisli[T, T],
) Operator[S, S]

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, struct{}]

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:

  1. Executes the source IO[A] to get a value
  2. Passes that value to the consumer for side effects
  3. 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

func ChainTo[A, B any](fb IO[B]) Operator[A, B]

ChainTo composes computations in sequence, ignoring the return value of the first computation

func Delay

func Delay[A any](delay time.Duration) Operator[A, A]

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

func LetL[S, T any](
	lens L.Lens[S, T],
	f func(T) T,
) Operator[S, S]

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

func LetToL[S, T any](
	lens L.Lens[S, T],
	b T,
) Operator[S, S]

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}]

func Map

func Map[A, B any](f func(A) B) Operator[A, B]

Map returns an operator that transforms the result of an IO computation. This is the curried version of MonadMap.

Example:

double := io.Map(N.Mul(2))
doubled := double(io.Of(21))

func MapTo

func MapTo[A, B any](b B) Operator[A, B]

MapTo returns an operator that replaces the result with a constant value. This is the curried version of MonadMapTo.

type Pair

type Pair[L, R any] = pair.Pair[L, R]

type RetryStatus

type RetryStatus = IO[R.RetryStatus]

RetryStatus is an IO computation that returns retry status information.

type Semigroup

type Semigroup[A any] = S.Semigroup[IO[A]]

func ApplySemigroup

func ApplySemigroup[A any](s S.Semigroup[A]) Semigroup[A]

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 Seq

type Seq[T any] = iter.Seq[T]

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL