Documentation
¶
Overview ¶
Package lens provides functional optics for zooming into and modifying nested data structures.
Overview ¶
A Lens is a first-class reference to a subpart of a data structure. It provides a composable way to focus on a particular field within a nested structure, allowing you to get and set values in an immutable, functional manner.
Lenses are particularly useful when working with deeply nested immutable data structures, as they eliminate the need for verbose copying and updating code.
Mathematical Foundation ¶
A Lens[S, A] is defined by two operations:
- Get: S → A (extract a value of type A from a structure of type S)
- Set: A → S → S (update the value of type A in structure S, returning a new S)
Lenses must satisfy the lens laws:
- GetSet: lens.Set(lens.Get(s))(s) == s
- SetGet: lens.Get(lens.Set(a)(s)) == a
- SetSet: lens.Set(a2)(lens.Set(a1)(s)) == lens.Set(a2)(s)
Basic Usage ¶
Creating a lens for a struct field:
type Person struct {
Name string
Age int
}
// Create a lens for the Name field
nameLens := lens.MakeLens(
func(p Person) string { return p.Name },
func(p Person, name string) Person {
p.Name = name
return p
},
)
person := Person{Name: "Alice", Age: 30}
// Get the name
name := nameLens.Get(person) // "Alice"
// Set a new name (returns a new Person)
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated.Name is "Bob"
Composing Lenses ¶
Lenses can be composed to focus on deeply nested fields:
type Address struct {
Street string
City string
}
type Person struct {
Name string
Address Address
}
addressLens := lens.MakeLens(
func(p Person) Address { return p.Address },
func(p Person, a Address) Person {
p.Address = a
return p
},
)
streetLens := lens.MakeLens(
func(a Address) string { return a.Street },
func(a Address, s string) Address {
a.Street = s
return a
},
)
// Compose to access street directly from person
personStreetLens := F.Pipe1(
addressLens,
lens.Compose[Person](streetLens),
)
person := Person{
Name: "Alice",
Address: Address{Street: "Main St", City: "NYC"},
}
street := personStreetLens.Get(person) // "Main St"
updated := personStreetLens.Set("Oak Ave")(person)
Working with Pointers ¶
For pointer-based structures, use MakeLensRef which handles copying automatically:
type Person struct {
Name string
Age int
}
func (p *Person) GetName() string {
return p.Name
}
func (p *Person) SetName(name string) *Person {
p.Name = name
return p
}
// MakeLensRef handles pointer copying
nameLens := lens.MakeLensRef(
(*Person).GetName,
(*Person).SetName,
)
person := &Person{Name: "Alice", Age: 30}
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer
Optional Values ¶
Lenses can work with optional values using Option types:
type Config struct {
Port *int
Timeout *int
}
portLens := lens.MakeLens(
func(c Config) *int { return c.Port },
func(c Config, p *int) Config {
c.Port = p
return c
},
)
// Convert to optional lens
optPortLens := lens.FromNillable(portLens)
config := Config{Port: nil}
// Get returns None for nil
port := optPortLens.Get(config) // None[*int]
// Set with Some updates the value
newPort := 8080
updated := optPortLens.Set(O.Some(&newPort))(config)
// Set with None removes the value
cleared := optPortLens.Set(O.None[*int]())(updated)
Composing with Optional Values ¶
ComposeOption allows composing a lens returning an optional value with a regular lens:
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}
// Compose with default value
configPortLens := F.Pipe1(
dbLens,
lens.ComposeOption[Config, int](defaultDB)(portLens),
)
config := Config{Database: nil}
// Get returns None when database is nil
port := configPortLens.Get(config) // None[int]
// Set creates database with default values
updated := configPortLens.Set(O.Some(3306))(config)
// updated.Database.Port == 3306, Host == "localhost"
Modifying Values ¶
Use Modify to transform a value through a lens:
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
},
)
counter := Counter{Value: 5}
// Increment the counter
incremented := F.Pipe2(
counter,
valueLens,
lens.Modify[Counter](func(v int) int { return v + 1 }),
)
// incremented.Value == 6
Identity Lens ¶
The identity lens focuses on the entire structure:
idLens := lens.Id[Person]()
person := Person{Name: "Alice", Age: 30}
same := idLens.Get(person) // returns person
updated := idLens.Set(Person{Name: "Bob", Age: 25})(person)
Isomorphic Mapping ¶
IMap allows you to transform the focus type of a lens:
type Celsius float64
type Fahrenheit float64
celsiusToFahrenheit := func(c Celsius) Fahrenheit {
return Fahrenheit(c*9/5 + 32)
}
fahrenheitToCelsius := func(f Fahrenheit) Celsius {
return Celsius((f - 32) * 5 / 9)
}
type Weather struct {
Temperature Celsius
}
tempCelsiusLens := lens.MakeLens(
func(w Weather) Celsius { return w.Temperature },
func(w Weather, t Celsius) Weather {
w.Temperature = t
return w
},
)
// Create a lens that works with Fahrenheit
tempFahrenheitLens := F.Pipe1(
tempCelsiusLens,
lens.IMap[Weather](celsiusToFahrenheit, fahrenheitToCelsius),
)
weather := Weather{Temperature: 20} // 20°C
tempF := tempFahrenheitLens.Get(weather) // 68°F
updated := tempFahrenheitLens.Set(86)(weather) // Set to 86°F (30°C)
Nullable Properties ¶
FromNullableProp creates a lens that provides a default value for nullable properties:
type Config struct {
Timeout *int
}
timeoutLens := lens.MakeLens(
func(c Config) *int { return c.Timeout },
func(c Config, t *int) Config {
c.Timeout = t
return c
},
)
// Provide default value of 30 for nil timeout
safeTimeoutLens := F.Pipe1(
timeoutLens,
lens.FromNullableProp[Config](
O.FromNillable[int],
func() *int { v := 30; return &v }(),
),
)
config := Config{Timeout: nil}
timeout := safeTimeoutLens.Get(config) // returns pointer to 30
FromOption ¶
FromOption creates a lens from an Option property, providing a default value:
type Settings struct {
MaxRetries O.Option[int]
}
retriesLens := lens.MakeLens(
func(s Settings) O.Option[int] { return s.MaxRetries },
func(s Settings, r O.Option[int]) Settings {
s.MaxRetries = r
return s
},
)
// Provide default of 3 retries
safeRetriesLens := F.Pipe1(
retriesLens,
lens.FromOption[Settings](3),
)
settings := Settings{MaxRetries: O.None[int]()}
retries := safeRetriesLens.Get(settings) // returns 3
updated := safeRetriesLens.Set(5)(settings) // sets to Some(5)
Predicate-Based Lenses ¶
FromPredicate creates an optional lens based on a predicate:
type User struct {
Age int
}
ageLens := lens.MakeLens(
func(u User) int { return u.Age },
func(u User, age int) User {
u.Age = age
return u
},
)
// Only consider valid ages (18+)
adultAgeLens := F.Pipe1(
ageLens,
lens.FromPredicate[User](func(age int) bool {
return age >= 18
}, 0),
)
user := User{Age: 25}
age := adultAgeLens.Get(user) // Some(25)
minor := User{Age: 15}
minorAge := adultAgeLens.Get(minor) // None[int]
Real-World Example: Configuration Management ¶
type DatabaseConfig struct {
Host string
Port int
Username string
Password string
}
type CacheConfig struct {
TTL int
MaxSize int
}
type AppConfig struct {
Database *DatabaseConfig
Cache *CacheConfig
Debug bool
}
// Create lenses for each level
dbLens := lens.FromNillable(lens.MakeLens(
func(c AppConfig) *DatabaseConfig { return c.Database },
func(c AppConfig, db *DatabaseConfig) AppConfig {
c.Database = db
return c
},
))
dbHostLens := lens.MakeLensRef(
func(db *DatabaseConfig) string { return db.Host },
func(db *DatabaseConfig, host string) *DatabaseConfig {
db.Host = host
return db
},
)
defaultDB := &DatabaseConfig{
Host: "localhost",
Port: 5432,
Username: "admin",
Password: "",
}
// Compose to access database host from app config
appDbHostLens := F.Pipe1(
dbLens,
lens.ComposeOption[AppConfig, string](defaultDB)(dbHostLens),
)
config := AppConfig{Database: nil, Debug: true}
// Get returns None when database is not configured
host := appDbHostLens.Get(config) // None[string]
// Set creates database with default values
updated := appDbHostLens.Set(O.Some("prod.example.com"))(config)
// updated.Database.Host == "prod.example.com"
// updated.Database.Port == 5432 (from default)
Performance Considerations ¶
Lenses create new copies of data structures on each Set operation. For deeply nested structures, this can be expensive. Consider:
1. Using pointer-based structures with MakeLensRef for better performance 2. Batching multiple updates using Modify 3. Using specialized lenses for common patterns (arrays, records, etc.)
Type Safety ¶
Lenses are fully type-safe. The compiler ensures that: - Get returns the correct type - Set accepts the correct type - Composed lenses maintain type relationships
Function Reference ¶
Core Lens Creation:
- MakeLens: Create a lens from getter and setter functions
- MakeLensCurried: Create a lens with curried setter
- MakeLensRef: Create a lens for pointer-based structures
- MakeLensRefCurried: Create a lens for pointers with curried setter
- MakeLensWithEq: Create a lens with equality optimization for pointer structures
- MakeLensStrict: Create a lens with strict equality optimization for pointer structures
- Id: Create an identity lens
- IdRef: Create an identity lens for pointers
Composition:
- Compose: Compose two lenses
- ComposeRef: Compose lenses for pointer structures
- ComposeOption: Compose lens returning Option with regular lens
- ComposeOptions: Compose two lenses returning Options
Transformation:
- Modify: Transform a value through a lens
- IMap: Transform the focus type of a lens
Optional Value Handling:
- FromNillable: Create optional lens from nullable pointer
- FromNillableRef: Create optional lens from nullable pointer (ref version)
- FromNullableProp: Create lens with default for nullable property
- FromNullablePropRef: Create lens with default for nullable property (ref version)
- FromOption: Create lens from Option property with default
- FromOptionRef: Create lens from Option property with default (ref version)
- FromPredicate: Create optional lens based on predicate
- FromPredicateRef: Create optional lens based on predicate (ref version)
Related Packages ¶
- github.com/IBM/fp-go/v2/optics/iso: Isomorphisms (bidirectional transformations)
- github.com/IBM/fp-go/v2/optics/prism: Prisms (focus on sum types)
- github.com/IBM/fp-go/v2/optics/optional: Optional optics
- github.com/IBM/fp-go/v2/optics/traversal: Traversals (focus on multiple values)
- github.com/IBM/fp-go/v2/option: Optional values
- github.com/IBM/fp-go/v2/endomorphism: Endomorphisms (A → A functions)
Lens is an optic used to zoom inside a product.
Package lens provides functional optics for zooming into and updating parts of immutable data structures.
A lens is a composable, first-class reference to a subpart of a data structure that enables getting and setting values in a purely functional way without mutation.
Index ¶
- func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Lens[S, A]) Endomorphism[S]
- type Endomorphism
- type Kleisli
- type Lens
- func Id[S any]() Lens[S, S]
- func IdRef[S any]() Lens[*S, *S]
- func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A]
- func MakeLensCurried[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET) Lens[S, A]
- func MakeLensCurriedRefWithName[GET ~func(*S) A, SET ~func(A) Endomorphism[*S], S, A any](get GET, set SET, name string) Lens[*S, A]
- func MakeLensCurriedWithName[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET, name string) Lens[S, A]
- func MakeLensRef[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET) Lens[*S, A]
- func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) Endomorphism[*S]) Lens[*S, A]
- func MakeLensRefCurriedWithName[S, A any](get func(*S) A, set func(A) Endomorphism[*S], name string) Lens[*S, A]
- func MakeLensRefWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET, name string) Lens[*S, A]
- func MakeLensStrict[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET) Lens[*S, A]
- func MakeLensStrictWithName[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET, name string) Lens[*S, A]
- func MakeLensWithEq[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET) Lens[*S, A]
- func MakeLensWithEqWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET, name string) Lens[*S, A]
- func MakeLensWithName[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET, name string) Lens[S, A]
- type Operator
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Modify ¶
func Modify[S any, FCT ~func(A) A, A any](f FCT) func(Lens[S, A]) Endomorphism[S]
Modify transforms a value through a lens using a transformation F.
Instead of setting a specific value, Modify applies a function to the current value. This is useful for updates like incrementing a counter, appending to a string, etc. If the transformation doesn't change the value, the original structure is returned.
Type Parameters:
- S: Structure type
- FCT: Transformation function type (A → A)
- A: Focus type
Parameters:
- f: Transformation function to apply to the focused value
Returns:
- A function that takes a Lens[S, A] and returns an Endomorphism[S]
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 },
)
counter := Counter{Value: 5}
// Increment the counter
incremented := F.Pipe2(
valueLens,
lens.Modify[Counter](func(v int) int { return v + 1 }),
F.Ap(counter),
)
// incremented.Value == 6
// Double the counter
doubled := F.Pipe2(
valueLens,
lens.Modify[Counter](func(v int) int { return v * 2 }),
F.Ap(counter),
)
// doubled.Value == 10
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.
type Kleisli ¶
Kleisli represents a function that takes a value of type A and returns a Lens[S, B]. This is useful for composing lenses in a monadic style, allowing for dynamic lens creation based on input values.
Type Parameters:
- S: The source/structure type
- A: The input type
- B: The focus type of the resulting lens
type Lens ¶
type Lens[S, A any] struct { // Get extracts the focused value of type A from structure S. Get func(s S) A // Set returns a function that updates the focused value in structure S. // The returned function takes a structure S and returns a new structure S // with the focused value updated to a. The original structure is never modified. Set func(a A) Endomorphism[S] // contains filtered or unexported fields }
Lens is a functional reference to a subpart of a data structure.
A Lens[S, A] provides a composable way to focus on a field of type A within a structure of type S. It consists of two operations:
- Get: Extracts the focused value from the structure (S → A)
- Set: Updates the focused value in the structure, returning a new structure (A → S → S)
Lenses maintain immutability by always returning new copies of the structure when setting values, never modifying the original.
Type Parameters:
- S: The source/structure type (the whole)
- A: The focus/field type (the part)
Lens Laws:
A well-behaved lens must satisfy three laws:
- GetSet (You get what you set): lens.Set(lens.Get(s))(s) == s
- SetGet (You set what you get): lens.Get(lens.Set(a)(s)) == a
- SetSet (Setting twice is the same as setting once): lens.Set(a2)(lens.Set(a1)(s)) == lens.Set(a2)(s)
Example Usage:
type Person struct {
Name string
Age int
}
// Create a lens focusing on the Name field
nameLens := lens.MakeLens(
func(p Person) string { return p.Name },
func(name string) func(Person) Person {
return func(p Person) Person {
return Person{Name: name, Age: p.Age}
}
},
)
person := Person{Name: "Alice", Age: 30}
name := nameLens.Get(person) // Returns: "Alice"
updated := nameLens.Set("Bob")(person) // Returns: Person{Name: "Bob", Age: 30}
// Original person remains unchanged (immutability preserved)
func Id ¶
func Id[S any]() Lens[S, S]
Id returns an identity Lens that focuses on the entire structure.
The identity lens is useful as a starting point for lens composition or when you need a lens that doesn't actually focus on a subpart. Get returns the structure unchanged, and Set replaces the entire structure.
Type Parameters:
- S: The structure type
Returns:
- A Lens[S, S] where both source and focus are the same type
Example:
type Person struct {
Name string
Age int
}
idLens := lens.Id[Person]()
person := Person{Name: "Alice", Age: 30}
same := idLens.Get(person) // Returns person unchanged
replaced := idLens.Set(Person{Name: "Bob", Age: 25})(person)
// replaced is Person{Name: "Bob", Age: 25}
func IdRef ¶
func IdRef[S any]() Lens[*S, *S]
IdRef returns an identity Lens for pointer-based structures.
This is the pointer version of Id. It focuses on the entire pointer structure, with automatic copying to ensure immutability.
Type Parameters:
- S: The structure type (will be used as *S)
Returns:
- A Lens[*S, *S] where both source and focus are pointers to the same type
Example:
idLens := lens.IdRef[Person]()
person := &Person{Name: "Alice", Age: 30}
same := idLens.Get(person) // Returns person pointer
replaced := idLens.Set(&Person{Name: "Bob", Age: 25})(person)
// person.Name is still "Alice", replaced is a new pointer
func MakeLens ¶
func MakeLens[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET) Lens[S, A]
MakeLens creates a Lens based on a getter and a setter F.
The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRef instead. For other reference types (slices, maps), ensure the setter creates a copy.
Type Parameters:
- GET: Getter function type (S → A)
- SET: Setter function type (S, A → S)
- S: Source structure type
- A: Focus/field type
Parameters:
- get: Function to extract value A from structure S
- set: Function to update value A in structure S, returning a new S
Returns:
- A Lens[S, A] that can get and set values immutably
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLens(
func(p Person) string { return p.Name },
func(p Person, name string) Person {
p.Name = name
return p
},
)
person := Person{Name: "Alice", Age: 30}
name := nameLens.Get(person) // "Alice"
updated := nameLens.Set("Bob")(person) // Person{Name: "Bob", Age: 30}
func MakeLensCurried ¶
func MakeLensCurried[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET) Lens[S, A]
MakeLensCurried creates a Lens with a curried setter F.
This is similar to MakeLens but accepts a curried setter (A → S → S) instead of an uncurried one (S, A → S). The curried form is more composable in functional pipelines.
The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRefCurried.
Type Parameters:
- GET: Getter function type (S → A)
- SET: Curried setter function type (A → S → S)
- S: Source structure type
- A: Focus/field type
Parameters:
- get: Function to extract value A from structure S
- set: Curried function to update value A in structure S
Returns:
- A Lens[S, A] that can get and set values immutably
Example:
nameLens := lens.MakeLensCurried(
func(p Person) string { return p.Name },
func(name string) func(Person) Person {
return func(p Person) Person {
p.Name = name
return p
}
},
)
func MakeLensCurriedRefWithName ¶ added in v2.1.20
func MakeLensCurriedRefWithName[GET ~func(*S) A, SET ~func(A) Endomorphism[*S], S, A any](get GET, set SET, name string) Lens[*S, A]
func MakeLensCurriedWithName ¶
func MakeLensCurriedWithName[GET ~func(S) A, SET ~func(A) Endomorphism[S], S, A any](get GET, set SET, name string) Lens[S, A]
MakeLensCurriedWithName creates a Lens with a curried setter and a custom name.
This combines the benefits of MakeLensCurried (curried setter for better composition) with MakeLensWithName (custom name for debugging). The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.
The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRefCurried.
Type Parameters:
- GET: Getter function type (S → A)
- SET: Curried setter function type (A → S → S)
- S: Source structure type
- A: Focus/field type
Parameters:
- get: Function to extract value A from structure S
- set: Curried function to update value A in structure S
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[S, A] with the specified name
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensCurriedWithName(
func(p Person) string { return p.Name },
func(name string) func(Person) Person {
return func(p Person) Person {
p.Name = name
return p
}
},
"Person.Name",
)
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
func MakeLensRef ¶
func MakeLensRef[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET) Lens[*S, A]
MakeLensRef creates a Lens for pointer-based structures.
Unlike MakeLens, the setter does not need to create a copy manually. This function automatically wraps the setter to create a shallow copy of the pointed-to value before modification, ensuring immutability.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
Returns:
- A Lens[*S, A] that can get and set values immutably on pointers
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensRef(
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
)
person := &Person{Name: "Alice", Age: 30}
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"
func MakeLensRefCurried ¶
func MakeLensRefCurried[S, A any](get func(*S) A, set func(A) Endomorphism[*S]) Lens[*S, A]
MakeLensRefCurried creates a Lens for pointer-based structures with a curried setter.
This combines the benefits of MakeLensRef (automatic copying) with MakeLensCurried (curried setter for better composition). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- get: Function to extract value A from pointer *S
- set: Curried function to update value A in pointer *S (copying handled automatically)
Returns:
- A Lens[*S, A] that can get and set values immutably on pointers
Example:
nameLens := lens.MakeLensRefCurried(
func(p *Person) string { return p.Name },
func(name string) func(*Person) *Person {
return func(p *Person) *Person {
p.Name = name // No manual copy needed
return p
}
},
)
func MakeLensRefCurriedWithName ¶
func MakeLensRefCurriedWithName[S, A any](get func(*S) A, set func(A) Endomorphism[*S], name string) Lens[*S, A]
MakeLensRefCurriedWithName creates a Lens for pointer-based structures with a curried setter and custom name.
This combines the benefits of MakeLensRefCurried (automatic copying with curried setter) with MakeLensWithName (custom name for debugging). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability. The curried form is more composable in functional pipelines, and the name is useful for debugging.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- get: Function to extract value A from pointer *S
- set: Curried function to update value A in pointer *S (copying handled automatically)
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[*S, A] with the specified name
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensRefCurriedWithName(
func(p *Person) string { return p.Name },
func(name string) func(*Person) *Person {
return func(p *Person) *Person {
p.Name = name // No manual copy needed
return p
}
},
"Person.Name",
)
person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"
func MakeLensRefWithName ¶
func MakeLensRefWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](get GET, set SET, name string) Lens[*S, A]
MakeLensRefWithName creates a Lens for pointer-based structures with a custom name.
This combines MakeLensRef (automatic copying for pointer structures) with MakeLensWithName (custom name for debugging). The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability. The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[*S, A] with the specified name
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensRefWithName(
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
"Person.Name",
)
person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"
func MakeLensStrict ¶
func MakeLensStrict[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET) Lens[*S, A]
MakeLensStrict creates a Lens for pointer-based structures with strict equality optimization.
This is a convenience function that combines MakeLensWithEq with strict equality comparison (==). It's suitable for comparable types (primitives, strings, pointers, etc.) and provides the same optimization as MakeLensWithEq: if the new value equals the current value, the original pointer is returned unchanged instead of creating a copy.
The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type (must be comparable)
Parameters:
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
Returns:
- A Lens[*S, A] that can get and set values immutably on pointers with strict equality optimization
Example:
type Person struct {
Name string
Age int
}
// Using MakeLensStrict for a string field (comparable type)
nameLens := lens.MakeLensStrict(
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
)
person := &Person{Name: "Alice", Age: 30}
// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)
// same == person (same pointer)
// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"
func MakeLensStrictWithName ¶
func MakeLensStrictWithName[GET ~func(*S) A, SET func(*S, A) *S, S any, A comparable](get GET, set SET, name string) Lens[*S, A]
MakeLensStrictWithName creates a Lens for pointer-based structures with strict equality optimization and a custom name.
This combines MakeLensStrict (strict equality optimization using ==) with MakeLensWithName (custom name for debugging). It's a convenience function suitable for comparable types (primitives, strings, pointers, etc.). If the new value equals the current value, the original pointer is returned unchanged instead of creating a copy. The name is useful for debugging.
The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type (must be comparable)
Parameters:
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[*S, A] with strict equality optimization and the specified name
Example:
type Person struct {
Name string
Age int
}
// Using MakeLensStrictWithName for a string field (comparable type)
nameLens := lens.MakeLensStrictWithName(
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
"Person.Name",
)
person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person) // same == person
// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person) // person.Name still "Alice"
func MakeLensWithEq ¶
func MakeLensWithEq[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET) Lens[*S, A]
MakeLensWithEq creates a Lens for pointer-based structures with equality optimization.
This is similar to MakeLensRef but includes an optimization: if the new value equals the current value (according to the provided Eq predicate), the original pointer is returned unchanged instead of creating a copy. This can improve performance and reduce allocations when setting values that don't actually change the structure.
The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- pred: Equality predicate to compare values of type A
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
Returns:
- A Lens[*S, A] that can get and set values immutably on pointers with equality optimization
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensWithEq(
eq.FromStrictEquals[string](),
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
)
person := &Person{Name: "Alice", Age: 30}
// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person)
// same == person (same pointer)
// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person)
// person.Name is still "Alice", updated is a new pointer with Name "Bob"
func MakeLensWithEqWithName ¶
func MakeLensWithEqWithName[GET ~func(*S) A, SET func(*S, A) *S, S, A any](pred EQ.Eq[A], get GET, set SET, name string) Lens[*S, A]
MakeLensWithEqWithName creates a Lens for pointer-based structures with equality optimization and a custom name.
This combines MakeLensWithEq (equality optimization) with MakeLensWithName (custom name for debugging). If the new value equals the current value (according to the provided Eq predicate), the original pointer is returned unchanged instead of creating a copy. The name is useful for debugging complex lens compositions.
The setter does not need to create a copy manually; this function automatically wraps it to ensure immutability when changes are made.
This lens assumes that property A always exists in structure S (i.e., it's not optional).
Type Parameters:
- GET: Getter function type (*S → A)
- SET: Setter function type (*S, A → *S)
- S: Source structure type (will be used as *S)
- A: Focus/field type
Parameters:
- pred: Equality predicate to compare values of type A
- get: Function to extract value A from pointer *S
- set: Function to update value A in pointer *S (copying handled automatically)
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[*S, A] with equality optimization and the specified name
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensWithEqWithName(
eq.FromStrictEquals[string](),
func(p *Person) string { return p.Name },
func(p *Person, name string) *Person {
p.Name = name // No manual copy needed
return p
},
"Person.Name",
)
person := &Person{Name: "Alice", Age: 30}
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
// Setting the same value returns the original pointer (no copy)
same := nameLens.Set("Alice")(person) // same == person
// Setting a different value creates a new copy
updated := nameLens.Set("Bob")(person) // person.Name still "Alice"
func MakeLensWithName ¶
func MakeLensWithName[GET ~func(S) A, SET ~func(S, A) S, S, A any](get GET, set SET, name string) Lens[S, A]
MakeLensWithName creates a Lens with a custom name for debugging and logging.
This is identical to MakeLens but allows you to specify a name that will be used when the lens is printed or formatted. The name is useful for debugging complex lens compositions and understanding which lens is being used in error messages or logs.
The setter must create a (shallow) copy of the data structure. This happens automatically when the data is passed by value. For pointer-based structures, use MakeLensRef instead.
Type Parameters:
- GET: Getter function type (S → A)
- SET: Setter function type (S, A → S)
- S: Source structure type
- A: Focus/field type
Parameters:
- get: Function to extract value A from structure S
- set: Function to update value A in structure S, returning a new S
- name: A descriptive name for the lens (used in String() and Format())
Returns:
- A Lens[S, A] with the specified name
Example:
type Person struct {
Name string
Age int
}
nameLens := lens.MakeLensWithName(
func(p Person) string { return p.Name },
func(p Person, name string) Person {
p.Name = name
return p
},
"Person.Name",
)
fmt.Printf("Using lens: %s\n", nameLens) // Prints: "Using lens: Person.Name"
func (Lens[S, T]) Format ¶
Format implements fmt.Formatter for Lens. Supports all standard format verbs:
- %s, %v, %+v: uses String() representation (lens name)
- %#v: uses GoString() representation
- %q: quoted String() representation
- other verbs: uses String() representation
Example:
nameLens := lens.MakeLensWithName(..., "Person.Name")
fmt.Printf("%s", nameLens) // "Person.Name"
fmt.Printf("%v", nameLens) // "Person.Name"
fmt.Printf("%#v", nameLens) // "lens.Lens[Person, string]{name: \"Person.Name\"}"
func (Lens[S, T]) GoString ¶
func (l Lens[S, T]) GoString() string
GoString implements fmt.GoStringer for Lens. Returns a Go-syntax representation of the Lens value.
Example:
nameLens := lens.MakeLensWithName(..., "Person.Name")
nameLens.GoString() // "lens.Lens[Person, string]{name: \"Person.Name\"}"
func (Lens[S, T]) LogValue ¶
LogValue implements slog.LogValuer for Lens. Returns a slog.Value that represents the Lens for structured logging. Logs the lens name as a string value.
Example:
logger := slog.Default()
nameLens := lens.MakeLensWithName(..., "Person.Name")
logger.Info("using lens", "lens", nameLens)
// Logs: {"msg":"using lens","lens":"Person.Name"}
type Operator ¶
Operator is a specialized Kleisli that takes a Lens[S, A] and returns a Lens[S, B]. This enables lens transformations and compositions where one lens is used to derive another.
Type Parameters:
- S: The source/structure type
- A: The focus type of the input lens
- B: The focus type of the resulting lens
func Compose ¶
func Compose[S, A, B any](ab Lens[A, B]) Operator[S, A, B]
Compose combines two lenses to focus on a deeply nested field.
Given a lens from S to A and a lens from A to B, Compose creates a lens from S to B. This allows you to navigate through nested structures in a composable way.
The composition follows the mathematical property: (sa ∘ ab).Get = ab.Get ∘ sa.Get
Type Parameters:
- S: Outer structure type
- A: Intermediate structure type
- B: Inner focus type
Parameters:
- ab: Lens from A to B (inner lens)
Returns:
- A function that takes a Lens[S, A] and returns a Lens[S, B]
Example:
type Address struct {
Street string
City string
}
type Person struct {
Name string
Address Address
}
addressLens := lens.MakeLens(
func(p Person) Address { return p.Address },
func(p Person, a Address) Person { p.Address = a; return p },
)
streetLens := lens.MakeLens(
func(a Address) string { return a.Street },
func(a Address, s string) Address { a.Street = s; return a },
)
// Compose to access street directly from person
personStreetLens := F.Pipe1(addressLens, lens.Compose[Person](streetLens))
person := Person{Name: "Alice", Address: Address{Street: "Main St"}}
street := personStreetLens.Get(person) // "Main St"
updated := personStreetLens.Set("Oak Ave")(person)
func ComposeRef ¶
func ComposeRef[S, A, B any](ab Lens[A, B]) Operator[*S, A, B]
ComposeRef combines two lenses for pointer-based structures.
This is the pointer version of Compose, automatically handling copying to ensure immutability. It allows you to navigate through nested pointer structures in a composable way.
Type Parameters:
- S: Outer structure type (will be used as *S)
- A: Intermediate structure type
- B: Inner focus type
Parameters:
- ab: Lens from A to B (inner lens)
Returns:
- A function that takes a Lens[*S, A] and returns a Lens[*S, B]
Example:
type Address struct {
Street string
}
type Person struct {
Name string
Address Address
}
addressLens := lens.MakeLensRef(
func(p *Person) Address { return p.Address },
func(p *Person, a Address) *Person { p.Address = a; return p },
)
streetLens := lens.MakeLens(
func(a Address) string { return a.Street },
func(a Address, s string) Address { a.Street = s; return a },
)
personStreetLens := F.Pipe1(addressLens, lens.ComposeRef[Person](streetLens))
func IMap ¶
IMap transforms the focus type of a lens using an isomorphism.
An isomorphism is a pair of functions (A → B, B → A) that are inverses of each other. IMap allows you to work with a lens in a different but equivalent type. This is useful for unit conversions, encoding/decoding, or any bidirectional transformation.
Type Parameters:
- E: Structure type
- AB: Forward transformation function type (A → B)
- BA: Backward transformation function type (B → A)
- A: Original focus type
- B: Transformed focus type
Parameters:
- ab: Forward transformation (A → B)
- ba: Backward transformation (B → A)
Returns:
- A function that takes a Lens[E, A] and returns a Lens[E, B]
Example:
type Celsius float64
type Fahrenheit float64
celsiusToFahrenheit := func(c Celsius) Fahrenheit {
return Fahrenheit(c*9/5 + 32)
}
fahrenheitToCelsius := func(f Fahrenheit) Celsius {
return Celsius((f - 32) * 5 / 9)
}
type Weather struct {
Temperature Celsius
}
tempCelsiusLens := lens.MakeLens(
func(w Weather) Celsius { return w.Temperature },
func(w Weather, t Celsius) Weather { w.Temperature = t; return w },
)
// Create a lens that works with Fahrenheit
tempFahrenheitLens := F.Pipe1(
tempCelsiusLens,
lens.IMap[Weather](celsiusToFahrenheit, fahrenheitToCelsius),
)
weather := Weather{Temperature: 20} // 20°C
tempF := tempFahrenheitLens.Get(weather) // 68°F
updated := tempFahrenheitLens.Set(86)(weather) // Set to 86°F (30°C)
Directories
¶
| Path | Synopsis |
|---|---|
|
Package iso provides utilities for composing lenses with isomorphisms.
|
Package iso provides utilities for composing lenses with isomorphisms. |
|
Package option provides utilities for working with lenses that focus on optional values.
|
Package option provides utilities for working with lenses that focus on optional values. |