option

package
v2.2.27 Latest Latest
Warning

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

Go to latest
Published: Feb 26, 2026 License: Apache-2.0 Imports: 10 Imported by: 0

Documentation

Overview

Package option provides utilities for working with lenses that focus on optional values.

This package extends the lens optics pattern to handle Option types, enabling safe manipulation of potentially absent values in nested data structures. It provides functions for creating, composing, and transforming lenses that work with optional fields.

Core Concepts

A LensO[S, A] is a Lens[S, Option[A]] - a lens that focuses on an optional value A within a structure S. This is particularly useful when dealing with nullable pointers, optional fields, or values that may not always be present.

Key Functions

Creating Lenses from Optional Values:

  • FromNillable: Creates a lens from a nullable pointer field
  • FromNillableRef: Pointer-based version of FromNillable
  • FromPredicate: Creates a lens based on a predicate function
  • FromPredicateRef: Pointer-based version of FromPredicate
  • FromOption: Converts an optional lens to a definite lens with a default value
  • FromOptionRef: Pointer-based version of FromOption
  • FromNullableProp: Creates a lens with a default value for nullable properties
  • FromNullablePropRef: Pointer-based version of FromNullableProp

Composing Lenses:

  • ComposeOption: Composes a lens returning Option[A] with a lens returning B
  • ComposeOptions: Composes two lenses that both return optional values

Conversions:

  • AsTraversal: Converts a lens to a traversal for use with traversal operations

Usage Examples

Working with nullable pointers:

type Config struct {
    Database *DatabaseConfig
}

type DatabaseConfig struct {
    Host string
    Port int
}

// Create a lens for the optional database config
dbLens := lens.FromNillable(lens.MakeLens(
    func(c Config) *DatabaseConfig { return c.Database },
    func(c Config, db *DatabaseConfig) Config { c.Database = db; return c },
))

// Access the optional value
config := Config{Database: nil}
dbOpt := dbLens.Get(config) // Returns None[*DatabaseConfig]

// Set a value
newDB := &DatabaseConfig{Host: "localhost", Port: 5432}
updated := dbLens.Set(O.Some(newDB))(config)

Composing optional lenses:

// Lens to access port through optional database
portLens := lens.MakeLensRef(
    func(db *DatabaseConfig) int { return db.Port },
    func(db *DatabaseConfig, port int) *DatabaseConfig { db.Port = port; return db },
)

defaultDB := &DatabaseConfig{Host: "localhost", Port: 5432}
configPortLens := F.Pipe1(dbLens,
    lens.ComposeOption[Config, int](defaultDB)(portLens))

// Get returns None if database is not set
port := configPortLens.Get(config) // None[int]

// Set creates the database with default values if needed
withPort := configPortLens.Set(O.Some(3306))(config)
// withPort.Database.Port == 3306, Host == "localhost"

Working with predicates:

type Person struct {
    Age int
}

ageLens := lens.MakeLensRef(
    func(p *Person) int { return p.Age },
    func(p *Person, age int) *Person { p.Age = age; return p },
)

// Only consider adults (age >= 18)
adultLens := lens.FromPredicateRef[Person](
    func(age int) bool { return age >= 18 },
    0, // nil value for non-adults
)(ageLens)

adult := &Person{Age: 25}
adultLens.Get(adult) // Some(25)

minor := &Person{Age: 15}
adultLens.Get(minor) // None[int]

Design Patterns

The package follows functional programming principles:

  • Immutability: All operations return new values rather than modifying in place
  • Composition: Lenses can be composed to access deeply nested optional values
  • Type Safety: The type system ensures correct usage at compile time
  • Lawful: All lenses satisfy the lens laws (get-put, put-get, put-put)

Performance Considerations

Lens operations are generally efficient, but composing many lenses can create function call overhead. For performance-critical code, consider:

  • Caching composed lenses rather than recreating them
  • Using direct field access for simple cases
  • Profiling to identify bottlenecks
  • github.com/IBM/fp-go/v2/optics/lens: Core lens functionality
  • github.com/IBM/fp-go/v2/option: Option type and operations
  • github.com/IBM/fp-go/v2/optics/traversal/option: Traversals for optional values

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AsTraversal

func AsTraversal[S, A any]() func(Lens[S, A]) T.Traversal[S, A]

AsTraversal converts a Lens[S, A] to a Traversal[S, A] for optional values.

A traversal is a generalization of a lens that can focus on zero or more values. This function converts a lens (which focuses on exactly one value) into a traversal, allowing it to be used with traversal operations like mapping over multiple values.

This is particularly useful when you want to:

  • Use lens operations in a traversal context
  • Compose lenses with traversals
  • Apply operations that work on collections of optional values

The conversion uses the Option monad's map operation to handle the optional nature of the values being traversed.

Type Parameters:

  • S: The structure type containing the field
  • A: The type of the field being focused on

Returns:

  • A function that takes a Lens[S, A] and returns a Traversal[S, A]

Example:

type Config struct {
    Timeout Option[int]
}

timeoutLens := lens.MakeLens(
    func(c Config) Option[int] { return c.Timeout },
    func(c Config, t Option[int]) Config { c.Timeout = t; return c },
)

// Convert to traversal for use with traversal operations
timeoutTraversal := lens.AsTraversal[Config, int]()(timeoutLens)

// Now can use traversal operations
configs := []Config{{Timeout: O.Some(30)}, {Timeout: O.None[int]()}}
// Apply operations across all configs using the traversal

func Compose

func Compose[S, B, A any](defaultA A) func(LensO[A, B]) Operator[S, A, B]

Compose composes two lenses that both return optional values.

This handles the case where both the intermediate structure A and the inner focus B are optional. The getter returns None[B] if either A or B is None. The setter behavior is:

  • Set(Some[B]) when A exists: Updates B in A
  • Set(Some[B]) when A doesn't exist: Creates A with defaultA and sets B
  • Set(None[B]) when A doesn't exist: Identity operation (no change)
  • Set(None[B]) when A exists: Removes B from A (sets it to None)

Type Parameters:

  • S: Outer structure type
  • B: Inner focus type (optional)
  • A: Intermediate structure type (optional)

Parameters:

  • defaultA: Default value for A when it doesn't exist but B needs to be set

Returns:

  • A function that takes a LensO[A, B] and returns a function that takes a LensO[S, A] and returns a LensO[S, B]

Example:

type Settings struct {
    MaxRetries *int
}

type Config struct {
    Settings *Settings
}

settingsLens := lens.FromNillable(lens.MakeLens(
    func(c Config) *Settings { return c.Settings },
    func(c Config, s *Settings) Config { c.Settings = s; return c },
))

retriesLens := lens.FromNillable(lens.MakeLensRef(
    func(s *Settings) *int { return s.MaxRetries },
    func(s *Settings, r *int) *Settings { s.MaxRetries = r; return s },
))

defaultSettings := &Settings{}
configRetriesLens := F.Pipe1(settingsLens,
    lens.Compose[Config, *int](defaultSettings)(retriesLens))

func ComposeOption

func ComposeOption[S, B, A any](defaultA A) func(Lens[A, B]) Operator[S, A, B]

ComposeOption composes a lens returning an optional value with a lens returning a definite value.

This is useful when you have an optional intermediate structure and want to focus on a field within it. The getter returns Option[B] because the container A might not exist. The setter behavior depends on the input:

  • Set(Some[B]): Updates B in A, creating A with defaultA if it doesn't exist
  • Set(None[B]): Removes A entirely (sets it to None[A])

Type Parameters:

  • S: Outer structure type
  • B: Inner focus type (definite value)
  • A: Intermediate structure type (optional)

Parameters:

  • defaultA: Default value for A when it doesn't exist but B needs to be set

Returns:

  • A function that takes a Lens[A, B] and returns a function that takes a LensO[S, A] and returns a LensO[S, B]

Example:

type Database struct {
    Host string
    Port int
}

type Config struct {
    Database *Database
}

dbLens := lens.FromNillable(lens.MakeLens(
    func(c Config) *Database { return c.Database },
    func(c Config, db *Database) Config { c.Database = db; return c },
))

portLens := lens.MakeLensRef(
    func(db *Database) int { return db.Port },
    func(db *Database, port int) *Database { db.Port = port; return db },
)

defaultDB := &Database{Host: "localhost", Port: 5432}
configPortLens := F.Pipe1(dbLens, lens.ComposeOption[Config, int](defaultDB)(portLens))

config := Config{Database: nil}
port := configPortLens.Get(config)  // None[int]
updated := configPortLens.Set(O.Some(3306))(config)
// updated.Database.Port == 3306, Host == "localhost" (from default)

func FromIso

func FromIso[S, A any](iso Iso[A, Option[A]]) func(Lens[S, A]) LensO[S, A]

FromIso converts a Lens[S, A] to a LensO[S, A] using an isomorphism.

This function takes an isomorphism between A and Option[A] and uses it to transform a regular lens into an optional lens. It's particularly useful when you have a custom isomorphism that defines how to convert between a value and its optional representation.

The isomorphism must satisfy the round-trip laws:

  1. iso.ReverseGet(iso.Get(a)) == a for all a: A
  2. iso.Get(iso.ReverseGet(opt)) == opt for all opt: Option[A]

Type Parameters:

  • S: The structure type containing the field
  • A: The type of the field being focused on

Parameters:

  • iso: An isomorphism between A and Option[A] that defines the conversion

Returns:

  • A function that takes a Lens[S, A] and returns a LensO[S, A]

Example:

type Config struct {
    timeout int
}

// Create a lens to the timeout field
timeoutLens := lens.MakeLens(
    func(c Config) int { return c.timeout },
    func(c Config, t int) Config { c.timeout = t; return c },
)

// Create an isomorphism that treats 0 as None
zeroAsNone := iso.MakeIso(
    func(t int) option.Option[int] {
        if t == 0 {
            return option.None[int]()
        }
        return option.Some(t)
    },
    func(opt option.Option[int]) int {
        return option.GetOrElse(func() int { return 0 })(opt)
    },
)

// Convert to optional lens
optTimeoutLens := FromIso[Config, int](zeroAsNone)(timeoutLens)

config := Config{timeout: 0}
opt := optTimeoutLens.Get(config)        // None[int]()
updated := optTimeoutLens.Set(option.Some(30))(config) // Config{timeout: 30}

Common Use Cases:

  • Converting between sentinel values (like 0, -1, "") and Option
  • Applying custom validation logic when converting to/from Option
  • Integrating with existing isomorphisms like FromNillable

See also:

  • FromPredicate: For predicate-based optional conversion
  • FromNillable: For pointer-based optional conversion
  • FromOption: For converting from optional to non-optional with defaults

func FromNullableProp

func FromNullableProp[S, A any](isNullable O.Kleisli[A, A], defaultValue A) lens.Operator[S, A, A]

FromNullableProp returns a `Lens` from a property that may be optional. The getter returns a default value for these items

func FromNullablePropRef

func FromNullablePropRef[S, A any](isNullable O.Kleisli[A, A], defaultValue A) lens.Operator[*S, A, A]

FromNullablePropRef returns a `Lens` from a property that may be optional. The getter returns a default value for these items

func FromOption

func FromOption[S, A any](defaultValue A) func(LensO[S, A]) Lens[S, A]

FromOption returns a `Lens` from an option property. The getter returns a default value the setter will always set the some option

func FromOptionRef

func FromOptionRef[S, A any](defaultValue A) func(LensO[*S, A]) Lens[*S, A]

FromOptionRef creates a lens from an Option property with a default value for pointer structures.

This is the pointer version of FromOption, with automatic copying to ensure immutability. The getter returns the value inside Some[A], or the defaultValue if it's None[A]. The setter always wraps the value in Some[A].

Type Parameters:

  • S: Structure type (will be used as *S)
  • A: Focus type

Parameters:

  • defaultValue: Value to return when the Option is None

Returns:

  • A function that takes a Lens[*S, Option[A]] and returns a Lens[*S, A]

func FromPredicate

func FromPredicate[S, A any](pred func(A) bool, nilValue A) func(sa Lens[S, A]) LensO[S, A]

FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional if the optional value is set then the nil value will be set instead

func FromPredicateRef

func FromPredicateRef[S, A any](pred func(A) bool, nilValue A) func(sa Lens[*S, A]) LensO[*S, A]

FromPredicateRef returns a `Lens` for a property accessibly as a getter and setter that can be optional if the optional value is set then the nil value will be set instead

Types

type Endomorphism

type Endomorphism[A any] = endomorphism.Endomorphism[A]

Endomorphism is a function from a type to itself (A → A). It represents transformations that preserve the type.

This is commonly used in lens setters to transform a structure by applying a function that takes and returns the same type.

Example:

increment := N.Add(1)
// increment is an Endomorphism[int]

type Iso

type Iso[S, A any] = iso.Iso[S, A]

Iso represents an isomorphism between types S and A. An isomorphism is a bidirectional transformation that preserves structure.

type Kleisli

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

Kleisli represents a Kleisli arrow for optional lenses. It's a function from A to LensO[S, B], used for composing optional lens operations.

type Lens

type Lens[S, A any] = lens.Lens[S, A]

Lens represents a functional reference to a field within a structure.

A Lens[S, A] provides a way to get and set a value of type A within a structure of type S in an immutable way. It consists of:

  • Get: S → A (retrieve the value)
  • Set: A → S → S (update the value, returning a new structure)

Lenses satisfy three laws:

  1. Get-Put: lens.Set(lens.Get(s))(s) == s
  2. Put-Get: lens.Get(lens.Set(a)(s)) == a
  3. Put-Put: lens.Set(b)(lens.Set(a)(s)) == lens.Set(b)(s)

Type Parameters:

  • S: The structure type containing the field
  • A: The type of the field being focused on

type LensO

type LensO[S, A any] = Lens[S, Option[A]]

LensO is a lens that focuses on an optional value.

A LensO[S, A] is equivalent to Lens[S, Option[A]], representing a lens that focuses on a value of type A that may or may not be present within a structure S.

This is particularly useful for:

  • Nullable pointer fields
  • Optional configuration values
  • Fields that may be conditionally present

The getter returns Option[A] (Some if present, None if absent). The setter takes Option[A] (Some to set, None to remove).

Type Parameters:

  • S: The structure type containing the optional field
  • A: The type of the optional value being focused on

Example:

type Config struct {
    Timeout *int
}

timeoutLens := lens.MakeLensRef(
    func(c *Config) *int { return c.Timeout },
    func(c *Config, t *int) *Config { c.Timeout = t; return c },
)

optLens := lens.FromNillableRef(timeoutLens)
// optLens is a LensO[*Config, *int]

func FromNillable

func FromNillable[S, A any](sa Lens[S, *A]) LensO[S, *A]

FromPredicate returns a `Lens` for a property accessibly as a getter and setter that can be optional if the optional value is set then the `nil` value will be set instead

func FromNillableRef

func FromNillableRef[S, A any](sa Lens[*S, *A]) LensO[*S, *A]

FromNillableRef returns a `Lens` for a property accessibly as a getter and setter that can be optional if the optional value is set then the `nil` value will be set instead

type Operator

type Operator[S, A, B any] = Kleisli[S, LensO[S, A], B]

Operator represents a function that transforms one optional lens into another. It takes a LensO[S, A] and produces a LensO[S, B].

type Option

type Option[T any] = option.Option[T]

Option represents a value that may or may not be present.

It is either Some[T] containing a value of type T, or None[T] representing the absence of a value. This is a type-safe alternative to using nil pointers.

Type Parameters:

  • T: The type of the value that may be present

Jump to

Keyboard shortcuts

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