lazy

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: 8 Imported by: 0

Documentation

Overview

Package lazy provides a functional programming abstraction for synchronous computations without side effects. It represents deferred computations that are evaluated only when their result is needed.

Fantasy Land Specification

This implementation corresponds to the Fantasy Land IO type (for pure computations): https://github.com/fantasyland/fantasy-land

Implemented Fantasy Land algebras:

Overview

A Lazy[A] is simply a function that takes no arguments and returns a value of type A:

type Lazy[A any] = func() A

This allows you to defer the evaluation of a computation until it's actually needed, which is useful for:

  • Avoiding unnecessary computations
  • Creating infinite data structures
  • Implementing memoization
  • Composing computations in a pure functional style

Core Concepts

The lazy package implements several functional programming patterns:

**Functor**: Transform values inside a Lazy context using Map

**Applicative**: Combine multiple Lazy computations using Ap and ApS

**Monad**: Chain dependent computations using Chain and Bind

**Memoization**: Cache computation results using Memoize

Basic Usage

Creating and evaluating lazy computations:

import (
    "fmt"
    "github.com/IBM/fp-go/v2/lazy"
    F "github.com/IBM/fp-go/v2/function"
)

// Create a lazy computation
computation := lazy.Of(42)

// Transform it
doubled := F.Pipe1(
    computation,
    lazy.Map(N.Mul(2)),
)

// Evaluate when needed
result := doubled() // 84

Memoization

Lazy computations can be memoized to ensure they're evaluated only once:

import "math/rand"

// Without memoization - generates different values each time
random := lazy.FromLazy(rand.Int)
value1 := random() // e.g., 12345
value2 := random() // e.g., 67890 (different)

// With memoization - caches the first result
memoized := lazy.Memoize(rand.Int)
value1 := memoized() // e.g., 12345
value2 := memoized() // 12345 (same as value1)

Chaining Computations

Use Chain to compose dependent computations:

getUserId := lazy.Of(123)

getUser := F.Pipe1(
    getUserId,
    lazy.Chain(func(id int) lazy.Lazy[User] {
        return lazy.Of(fetchUser(id))
    }),
)

user := getUser()

Do-Notation Style

The package supports do-notation style composition using Bind and ApS:

type Config struct {
    Host string
    Port int
}

result := F.Pipe2(
    lazy.Do(Config{}),
    lazy.Bind(
        func(host string) func(Config) Config {
            return func(c Config) Config { c.Host = host; return c }
        },
        func(c Config) lazy.Lazy[string] {
            return lazy.Of("localhost")
        },
    ),
    lazy.Bind(
        func(port int) func(Config) Config {
            return func(c Config) Config { c.Port = port; return c }
        },
        func(c Config) lazy.Lazy[int] {
            return lazy.Of(8080)
        },
    ),
)

config := result() // Config{Host: "localhost", Port: 8080}

Traverse and Sequence

Transform collections of values into lazy computations:

// Transform array elements
numbers := []int{1, 2, 3}
doubled := F.Pipe1(
    numbers,
    lazy.TraverseArray(func(x int) lazy.Lazy[int] {
        return lazy.Of(x * 2)
    }),
)
result := doubled() // []int{2, 4, 6}

// Sequence array of lazy computations
computations := []lazy.Lazy[int]{
    lazy.Of(1),
    lazy.Of(2),
    lazy.Of(3),
}
result := lazy.SequenceArray(computations)() // []int{1, 2, 3}

Retry Logic

The package includes retry functionality for computations that may fail:

import (
    R "github.com/IBM/fp-go/v2/retry"
    "time"
)

policy := R.CapDelay(
    2*time.Second,
    R.Monoid.Concat(
        R.ExponentialBackoff(10),
        R.LimitRetries(5),
    ),
)

action := func(status R.RetryStatus) lazy.Lazy[string] {
    return lazy.Of(fetchData())
}

check := func(value string) bool {
    return value == "" // retry if empty
}

result := lazy.Retrying(policy, action, check)()

Algebraic Structures

The package provides algebraic structures for combining lazy computations:

**Semigroup**: Combine two lazy values using a semigroup operation

import M "github.com/IBM/fp-go/v2/monoid"

intAddSemigroup := lazy.ApplySemigroup(M.MonoidSum[int]())
result := intAddSemigroup.Concat(lazy.Of(5), lazy.Of(10))() // 15

**Monoid**: Combine lazy values with an identity element

intAddMonoid := lazy.ApplicativeMonoid(M.MonoidSum[int]())
empty := intAddMonoid.Empty()() // 0
result := intAddMonoid.Concat(lazy.Of(5), lazy.Of(10))() // 15

Comparison

Compare lazy computations by evaluating and comparing their results:

import EQ "github.com/IBM/fp-go/v2/eq"

eq := lazy.Eq(EQ.FromEquals[int]())
result := eq.Equals(lazy.Of(42), lazy.Of(42)) // true

Key Functions

**Creation**:

  • Of: Create a lazy computation from a value
  • FromLazy: Create a lazy computation from another lazy computation
  • FromImpure: Convert a side effect into a lazy computation
  • Defer: Create a lazy computation from a generator function

**Transformation**:

  • Map: Transform the value inside a lazy computation
  • MapTo: Replace the value with a constant
  • Chain: Chain dependent computations
  • ChainFirst: Chain computations but keep the first result
  • Flatten: Flatten nested lazy computations

**Combination**:

  • Ap: Apply a lazy function to a lazy value
  • ApFirst: Combine two computations, keeping the first result
  • ApSecond: Combine two computations, keeping the second result

**Memoization**:

  • Memoize: Cache the result of a computation

**Do-Notation**:

  • Do: Start a do-notation context
  • Bind: Bind a computation result to a context
  • Let: Attach a pure value to a context
  • LetTo: Attach a constant to a context
  • BindTo: Initialize a context from a value
  • ApS: Attach a value using applicative style

**Lens-Based Operations**:

  • BindL: Bind using a lens
  • LetL: Let using a lens
  • LetToL: LetTo using a lens
  • ApSL: ApS using a lens

**Collections**:

  • TraverseArray: Transform array elements into lazy computations
  • SequenceArray: Convert array of lazy computations to lazy array
  • TraverseRecord: Transform record values into lazy computations
  • SequenceRecord: Convert record of lazy computations to lazy record

**Tuples**:

  • SequenceT1, SequenceT2, SequenceT3, SequenceT4: Combine lazy computations into tuples

**Retry**:

  • Retrying: Retry a computation according to a policy

**Algebraic**:

  • ApplySemigroup: Create a semigroup for lazy values
  • ApplicativeMonoid: Create a monoid for lazy values
  • Eq: Create an equality predicate for lazy values

Relationship to IO

The lazy package is built on top of the io package and shares the same underlying implementation. The key difference is conceptual:

  • lazy.Lazy[A] represents a pure, synchronous computation without side effects
  • io.IO[A] represents a computation that may have side effects

In practice, they are the same type, but the lazy package provides a more focused API for pure computations.

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Ap

func Ap[B, A any](ma Lazy[A]) func(Lazy[func(A) B]) Lazy[B]

Ap applies a lazy function to a lazy value. Returns a function that takes a lazy function and returns a lazy result.

This is the curried version of MonadAp, useful for function composition.

Example:

lazyValue := lazy.Of(5)
applyTo5 := lazy.Ap[int](lazyValue)
lazyFunc := lazy.Of(N.Mul(2))
result := applyTo5(lazyFunc)() // 10

func ApplicativeMonoid

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

ApplicativeMonoid lifts a Monoid[A] to a Monoid[Lazy[A]]. This allows you to combine lazy computations using the monoid operation on their underlying values, with an identity element.

The resulting monoid's Concat operation will evaluate both lazy computations and combine their results using the original monoid's operation. The Empty operation returns a lazy computation that produces the monoid's identity element.

Parameters:

  • m: A monoid for values of type A

Returns:

  • A monoid for lazy computations of type A

Example:

import (
    M "github.com/IBM/fp-go/v2/monoid"
    "github.com/IBM/fp-go/v2/lazy"
)

// Create a monoid for lazy integers using addition
intAddMonoid := lazy.ApplicativeMonoid(M.MonoidSum[int]())

// Get the identity element (0 wrapped in lazy)
empty := intAddMonoid.Empty()() // 0

lazy1 := lazy.Of(5)
lazy2 := lazy.Of(10)

// Combine the lazy computations
result := intAddMonoid.Concat(lazy1, lazy2)() // 15

// Identity laws hold:
// Concat(Empty(), x) == x
// Concat(x, Empty()) == x

func ApplySemigroup

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

ApplySemigroup lifts a Semigroup[A] to a Semigroup[Lazy[A]]. This allows you to combine lazy computations using the semigroup operation on their underlying values.

The resulting semigroup's Concat operation will evaluate both lazy computations and combine their results using the original semigroup's operation.

Parameters:

  • s: A semigroup for values of type A

Returns:

  • A semigroup for lazy computations of type A

Example:

import (
    M "github.com/IBM/fp-go/v2/monoid"
    "github.com/IBM/fp-go/v2/lazy"
)

// Create a semigroup for lazy integers using addition
intAddSemigroup := lazy.ApplySemigroup(M.MonoidSum[int]())

lazy1 := lazy.Of(5)
lazy2 := lazy.Of(10)

// Combine the lazy computations
result := intAddSemigroup.Concat(lazy1, lazy2)() // 15

func Eq

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

Eq implements the equals predicate for values contained in the IO monad

func Map

func Map[A, B any](f func(A) B) func(fa Lazy[A]) Lazy[B]

Map transforms the value inside a lazy computation using the provided function. Returns a function that can be applied to a lazy computation.

This is the curried version of MonadMap, useful for function composition.

Example:

double := lazy.Map(N.Mul(2))
computation := lazy.Of(5)
result := double(computation)() // 10

// Or with pipe:
result := F.Pipe1(lazy.Of(5), double)() // 10

Types

type Kleisli

type Kleisli[A, B any] = func(A) Lazy[B]

Kleisli represents a function that takes a value of type A and returns a lazy computation producing a value of type B.

Kleisli arrows are used for composing monadic computations. They allow you to chain operations where each step depends on the result of the previous step.

Example:

// A Kleisli arrow that doubles a number lazily
double := func(x int) lazy.Lazy[int] {
    return lazy.Of(x * 2)
}

// Chain it with another operation
result := lazy.Chain(double)(lazy.Of(5))() // 10

func ApFirst

func ApFirst[A, B any](second Lazy[B]) Kleisli[Lazy[A], A]

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

func ApS

func ApS[S1, S2, T any](
	setter func(T) func(S1) S2,
	fa Lazy[T],
) Kleisli[Lazy[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 rather than Monad). This allows independent computations to be combined without one depending on the result of the other.

Unlike Bind, which sequences operations, ApS can be used when operations are independent and can conceptually run in parallel.

Example:

type State struct {
    Config  Config
    Data    Data
}

// These operations are independent and can be combined with ApS
getConfig := lazy.MakeLazy(func() Config { return loadConfig() })
getData := lazy.MakeLazy(func() Data { return loadData() })

result := F.Pipe2(
    lazy.Do(State{}),
    lazy.ApS(
        func(cfg Config) func(State) State {
            return func(s State) State { s.Config = cfg; return s }
        },
        getConfig,
    ),
    lazy.ApS(
        func(data Data) func(State) State {
            return func(s State) State { s.Data = data; return s }
        },
        getData,
    ),
)

func ApSL

func ApSL[S, T any](
	lens L.Lens[S, T],
	fa Lazy[T],
) Kleisli[Lazy[S], S]

ApSL is a variant of ApS that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. This allows you to work with nested fields without manually managing the update logic.

Example:

type Config struct {
    Host string
    Port int
}
type State struct {
    Config Config
    Data   string
}

configLens := L.Prop[State, Config]("Config")
getConfig := lazy.MakeLazy(func() Config { return Config{Host: "localhost", Port: 8080} })

result := F.Pipe2(
    lazy.Do(State{}),
    lazy.ApSL(configLens, getConfig),
)

func ApSecond

func ApSecond[A, B any](second Lazy[B]) Kleisli[Lazy[A], B]

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

func Bind

func Bind[S1, S2, T any](
	setter func(T) func(S1) S2,
	f Kleisli[S1, T],
) Kleisli[Lazy[S1], S2]

Bind attaches the result of a computation to a context [S1] to produce a context [S2]. This enables sequential composition where each step can depend on the results of previous steps.

The setter function takes the result of the computation and returns a function that updates the context from S1 to S2.

Example:

type State struct {
    Config Config
    Data   Data
}

result := F.Pipe2(
    lazy.Do(State{}),
    lazy.Bind(
        func(cfg Config) func(State) State {
            return func(s State) State { s.Config = cfg; return s }
        },
        func(s State) lazy.Lazy[Config] {
            return lazy.MakeLazy(func() Config { return loadConfig() })
        },
    ),
    lazy.Bind(
        func(data Data) func(State) State {
            return func(s State) State { s.Data = data; return s }
        },
        func(s State) lazy.Lazy[Data] {
            // This can access s.Config from the previous step
            return lazy.MakeLazy(func() Data { return loadData(s.Config) })
        },
    ),
)

func BindL

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

BindL is a variant of Bind that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. The function f receives the current value of the focused field and returns a new computation that produces an updated value.

Example:

type Config struct {
    Host string
    Port int
}
type State struct {
    Config Config
    Data   string
}

configLens := L.Prop[State, Config]("Config")

result := F.Pipe2(
    lazy.Do(State{Config: Config{Host: "localhost"}}),
    lazy.BindL(configLens, func(cfg Config) lazy.Lazy[Config] {
        return lazy.MakeLazy(func() Config {
            cfg.Port = 8080
            return cfg
        })
    }),
)

func BindTo

func BindTo[S1, T any](
	setter func(T) S1,
) Kleisli[Lazy[T], S1]

BindTo initializes a new state [S1] from a value [T]

func Chain

func Chain[A, B any](f Kleisli[A, B]) Kleisli[Lazy[A], B]

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

func ChainFirst

func ChainFirst[A, B any](f Kleisli[A, B]) Kleisli[Lazy[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 Lazy[B]) Kleisli[Lazy[A], B]

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

func Let

func Let[S1, S2, T any](
	setter func(T) func(S1) S2,
	f func(S1) T,
) Kleisli[Lazy[S1], S2]

Let attaches the result of a computation to a context [S1] to produce a context [S2]

func LetL

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

LetL is a variant of Let that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. The function f receives the current value of the focused field and returns a new value (without wrapping in a monad).

Example:

type Config struct {
    Host string
    Port int
}
type State struct {
    Config Config
    Data   string
}

configLens := L.Prop[State, Config]("Config")

result := F.Pipe2(
    lazy.Do(State{Config: Config{Host: "localhost"}}),
    lazy.LetL(configLens, func(cfg Config) Config {
        cfg.Port = 8080
        return cfg
    }),
)

func LetTo

func LetTo[S1, S2, T any](
	setter func(T) func(S1) S2,
	b T,
) Kleisli[Lazy[S1], S2]

LetTo attaches the a value to a context [S1] to produce a context [S2]

func LetToL

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

LetToL is a variant of LetTo that uses a lens to focus on a specific part of the context. This provides a more ergonomic API when working with nested structures, eliminating the need to manually write setter functions.

The lens parameter provides both a getter and setter for a field of type T within the context S. The value b is set directly to the focused field.

Example:

type Config struct {
    Host string
    Port int
}
type State struct {
    Config Config
    Data   string
}

configLens := L.Prop[State, Config]("Config")
newConfig := Config{Host: "localhost", Port: 8080}

result := F.Pipe2(
    lazy.Do(State{}),
    lazy.LetToL(configLens, newConfig),
)

func MapTo

func MapTo[A, B any](b B) Kleisli[Lazy[A], B]

MapTo replaces the value inside a lazy computation with a constant value. Returns a function that can be applied to a lazy computation.

This is the curried version of MonadMapTo.

Example:

replaceWith42 := lazy.MapTo[string](42)
computation := lazy.Of("ignored")
result := replaceWith42(computation)() // 42

func TraverseArray

func TraverseArray[A, B any](f Kleisli[A, B]) Kleisli[[]A, []B]

TraverseArray applies a function returning an [IO] to all elements in an array and the transforms this into an [IO] of that array

func TraverseArrayWithIndex

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

TraverseArrayWithIndex applies a function returning an [IO] to all elements in an array and the transforms this into an [IO] of that array

func TraverseRecord

func TraverseRecord[K comparable, A, B any](f Kleisli[A, B]) Kleisli[map[K]A, map[K]B]

TraverseRecord applies a function returning an [IO] to all elements in a record and the transforms this into an [IO] of that record

func TraverseRecordWithIndex

func TraverseRecordWithIndex[K comparable, A, B any](f func(K, A) Lazy[B]) Kleisli[map[K]A, map[K]B]

TraverseRecord applies a function returning an [IO] to all elements in a record and the transforms this into an [IO] of that record

type Lazy

type Lazy[A any] = func() A

Lazy represents a synchronous computation without side effects. It is a function that takes no arguments and returns a value of type A.

Lazy computations are evaluated only when their result is needed (lazy evaluation). This allows for:

  • Deferring expensive computations until they're actually required
  • Creating infinite data structures
  • Implementing memoization patterns
  • Composing pure computations in a functional style

Example:

// Create a lazy computation
computation := lazy.Of(42)

// Transform it (not evaluated yet)
doubled := lazy.Map(N.Mul(2))(computation)

// Evaluate when needed
result := doubled() // 84

Note: Lazy is an alias for io.IO[A] but represents pure computations without side effects, whereas IO represents computations that may have side effects.

Example (Creation)
// lazy function of a constant value
val := Of(42)
// create another function to transform this
valS := F.Pipe1(
	val,
	Map(strconv.Itoa),
)

fmt.Println(valS())
Output:

42
var Now Lazy[time.Time] = io.Now

Now is a lazy computation that returns the current timestamp when evaluated. Each evaluation will return the current time at the moment of evaluation.

Example:

time1 := lazy.Now()
// ... some time passes ...
time2 := lazy.Now()
// time1 and time2 will be different

func Defer

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

Defer creates an IO by creating a brand new IO via a generator function, each time

func Do

func Do[S any](
	empty S,
) Lazy[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 {
    Config Config
    Data   Data
}
result := lazy.Do(State{})

func Flatten

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

func FromImpure

func FromImpure(f func()) Lazy[any]

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

func FromLazy

func FromLazy[A any](a Lazy[A]) Lazy[A]

FromLazy creates a lazy computation from another lazy computation. This is an identity function that can be useful for type conversions or making the intent explicit in code.

Example:

original := func() int { return 42 }
wrapped := lazy.FromLazy(original)
result := wrapped() // 42

func Memoize

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

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

func MonadAp

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

MonadAp applies a lazy function to a lazy value. Both the function and the value are evaluated when the result is evaluated.

This is the applicative functor operation, allowing you to apply functions that are themselves wrapped in a lazy context.

Example:

lazyFunc := lazy.Of(N.Mul(2))
lazyValue := lazy.Of(5)
result := lazy.MonadAp(lazyFunc, lazyValue)() // 10

func MonadApFirst

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

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

func MonadApSecond

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

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

func MonadChain

func MonadChain[A, B any](fa Lazy[A], f Kleisli[A, B]) Lazy[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 Lazy[A], f Kleisli[A, B]) Lazy[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 Lazy[A], fb Lazy[B]) Lazy[B]

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

func MonadMap

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

MonadMap transforms the value inside a lazy computation using the provided function. The transformation is not applied until the lazy computation is evaluated.

This is the monadic version of Map, taking the lazy computation as the first parameter.

Example:

computation := lazy.Of(5)
doubled := lazy.MonadMap(computation, N.Mul(2))
result := doubled() // 10

func MonadMapTo

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

MonadMapTo replaces the value inside a lazy computation with a constant value. The original computation is still evaluated, but its result is discarded.

This is useful when you want to sequence computations but only care about the side effects (though Lazy should represent pure computations).

Example:

computation := lazy.Of("ignored")
replaced := lazy.MonadMapTo(computation, 42)
result := replaced() // 42

func MonadOf

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

MonadOf creates a lazy computation that returns the given value. This is an alias for Of, provided for consistency with monadic naming conventions.

Example:

computation := lazy.MonadOf(42)
result := computation() // 42

func MonadTraverseArray

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

MonadTraverseArray applies a function returning a lazy computation to all elements in an array and transforms this into a lazy computation of that array.

This is the monadic version of TraverseArray, taking the array as the first parameter.

Example:

numbers := []int{1, 2, 3}
result := lazy.MonadTraverseArray(numbers, func(x int) lazy.Lazy[int] {
    return lazy.Of(x * 2)
})()
// result is []int{2, 4, 6}

func MonadTraverseRecord

func MonadTraverseRecord[K comparable, A, B any](tas map[K]A, f Kleisli[A, B]) Lazy[map[K]B]

MonadTraverseRecord applies a function returning a lazy computation to all values in a record (map) and transforms this into a lazy computation of that record.

This is the monadic version of TraverseRecord, taking the record as the first parameter.

Example:

record := map[string]int{"a": 1, "b": 2}
result := lazy.MonadTraverseRecord(record, func(x int) lazy.Lazy[int] {
    return lazy.Of(x * 2)
})()
// result is map[string]int{"a": 2, "b": 4}

func Of

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

Of creates a lazy computation that returns the given value. This is the most basic way to lift a value into the Lazy context.

The computation is pure and will always return the same value when evaluated.

Example:

computation := lazy.Of(42)
result := computation() // 42

func Retrying

func Retrying[A any](
	policy R.RetryPolicy,
	action Kleisli[R.RetryStatus, A],
	check func(A) bool,
) Lazy[A]

Retrying will retry the actions according to the check policy

policy - refers to the retry policy action - converts a status into an operation to be executed check - checks if the result of the action needs to be retried

func SequenceArray

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

SequenceArray converts an array of [IO] to an [IO] of an array

func SequenceRecord

func SequenceRecord[K comparable, A any](tas map[K]Lazy[A]) Lazy[map[K]A]

SequenceRecord converts a record of [IO] to an [IO] of a record

func SequenceT1

func SequenceT1[A any](a Lazy[A]) Lazy[tuple.Tuple1[A]]

SequenceT1 combines a single lazy computation into a lazy tuple. This is mainly useful for consistency with the other SequenceT functions.

Example:

lazy1 := lazy.Of(42)
result := lazy.SequenceT1(lazy1)()
// result is tuple.Tuple1[int]{F1: 42}

func SequenceT2

func SequenceT2[A, B any](a Lazy[A], b Lazy[B]) Lazy[tuple.Tuple2[A, B]]

SequenceT2 combines two lazy computations into a lazy tuple of two elements. Both computations are evaluated when the result is evaluated.

Example:

lazy1 := lazy.Of(42)
lazy2 := lazy.Of("hello")
result := lazy.SequenceT2(lazy1, lazy2)()
// result is tuple.Tuple2[int, string]{F1: 42, F2: "hello"}

func SequenceT3

func SequenceT3[A, B, C any](a Lazy[A], b Lazy[B], c Lazy[C]) Lazy[tuple.Tuple3[A, B, C]]

SequenceT3 combines three lazy computations into a lazy tuple of three elements. All computations are evaluated when the result is evaluated.

Example:

lazy1 := lazy.Of(42)
lazy2 := lazy.Of("hello")
lazy3 := lazy.Of(true)
result := lazy.SequenceT3(lazy1, lazy2, lazy3)()
// result is tuple.Tuple3[int, string, bool]{F1: 42, F2: "hello", F3: true}

func SequenceT4

func SequenceT4[A, B, C, D any](a Lazy[A], b Lazy[B], c Lazy[C], d Lazy[D]) Lazy[tuple.Tuple4[A, B, C, D]]

SequenceT4 combines four lazy computations into a lazy tuple of four elements. All computations are evaluated when the result is evaluated.

Example:

lazy1 := lazy.Of(42)
lazy2 := lazy.Of("hello")
lazy3 := lazy.Of(true)
lazy4 := lazy.Of(3.14)
result := lazy.SequenceT4(lazy1, lazy2, lazy3, lazy4)()
// result is tuple.Tuple4[int, string, bool, float64]{F1: 42, F2: "hello", F3: true, F4: 3.14}

type Operator

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

Operator represents a function that takes a lazy computation of type A and returns a lazy computation of type B.

Operators are used to transform lazy computations. They are essentially Kleisli arrows where the input is already wrapped in a Lazy context.

Example:

// An operator that doubles the value in a lazy computation
doubleOp := lazy.Map(N.Mul(2))

// Apply it to a lazy computation
result := doubleOp(lazy.Of(5))() // 10

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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