1
0
mirror of https://github.com/IBM/fp-go.git synced 2025-11-23 22:14:53 +02:00
Files
fp-go/v2/optics/lens/iso/doc.go
Dr. Carsten Leue d586428cb0 fix: examples
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
2025-11-13 09:05:57 +01:00

367 lines
8.7 KiB
Go

// Copyright (c) 2023 - 2025 IBM Corp.
// All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
Package iso provides utilities for composing lenses with isomorphisms.
# Overview
This package bridges lenses and isomorphisms, allowing you to transform the focus type
of a lens using an isomorphism. It provides functions to compose lenses with isomorphisms
and to create isomorphisms for common patterns like nullable pointers.
The key insight is that if you have a Lens[S, A] and an Iso[A, B], you can create a
Lens[S, B] by composing them. This allows you to work with transformed views of your
data without changing the underlying structure.
# Core Functions
## FromNillable
Creates an isomorphism between a nullable pointer and an Option type:
type Config struct {
Timeout *int
}
// Create isomorphism: *int ↔ Option[int]
timeoutIso := iso.FromNillable[int]()
// nil → None, &value → Some(value)
opt := timeoutIso.Get(nil) // None[int]
num := 42
opt = timeoutIso.Get(&num) // Some(42)
// None → nil, Some(value) → &value
ptr := timeoutIso.ReverseGet(O.None[int]()) // nil
ptr = timeoutIso.ReverseGet(O.Some(42)) // &42
## Compose
Composes a lens with an isomorphism to transform the focus type:
type Person struct {
Name string
Age int
}
type Celsius float64
type Fahrenheit float64
type Weather struct {
Temperature Celsius
}
// Lens to access temperature
tempLens := L.MakeLens(
func(w Weather) Celsius { return w.Temperature },
func(w Weather, t Celsius) Weather {
w.Temperature = t
return w
},
)
// Isomorphism: Celsius ↔ Fahrenheit
celsiusToFahrenheit := I.MakeIso(
func(c Celsius) Fahrenheit { return Fahrenheit(c*9/5 + 32) },
func(f Fahrenheit) Celsius { return Celsius((f - 32) * 5 / 9) },
)
// Compose to work with Fahrenheit
tempFahrenheitLens := F.Pipe1(
tempLens,
iso.Compose[Weather, Celsius, Fahrenheit](celsiusToFahrenheit),
)
weather := Weather{Temperature: 20} // 20°C
tempF := tempFahrenheitLens.Get(weather) // 68°F
updated := tempFahrenheitLens.Set(86)(weather) // Set to 86°F (30°C)
# Use Cases
## Working with Nullable Fields
Convert between nullable pointers and Option types:
type DatabaseConfig struct {
Host string
Port int
Username string
Password *string // Nullable
}
type AppConfig struct {
Database *DatabaseConfig
}
// Lens to database config
dbLens := L.MakeLens(
func(c AppConfig) *DatabaseConfig { return c.Database },
func(c AppConfig, db *DatabaseConfig) AppConfig {
c.Database = db
return c
},
)
// Isomorphism for nullable pointer
dbIso := iso.FromNillable[DatabaseConfig]()
// Compose to work with Option
dbOptLens := F.Pipe1(
dbLens,
iso.Compose[AppConfig, *DatabaseConfig, O.Option[DatabaseConfig]](dbIso),
)
config := AppConfig{Database: nil}
dbOpt := dbOptLens.Get(config) // None[DatabaseConfig]
// Set with Some
newDB := DatabaseConfig{Host: "localhost", Port: 5432}
updated := dbOptLens.Set(O.Some(newDB))(config)
## Unit Conversions
Work with different units of measurement:
type Distance struct {
Meters float64
}
type Kilometers float64
type Miles float64
// Lens to meters
metersLens := L.MakeLens(
func(d Distance) float64 { return d.Meters },
func(d Distance, m float64) Distance {
d.Meters = m
return d
},
)
// Isomorphism: meters ↔ kilometers
metersToKm := I.MakeIso(
func(m float64) Kilometers { return Kilometers(m / 1000) },
func(km Kilometers) float64 { return float64(km * 1000) },
)
// Compose to work with kilometers
kmLens := F.Pipe1(
metersLens,
iso.Compose[Distance, float64, Kilometers](metersToKm),
)
distance := Distance{Meters: 5000}
km := kmLens.Get(distance) // 5 km
updated := kmLens.Set(Kilometers(10))(distance) // 10000 meters
## Type Wrappers
Work with newtype wrappers:
type UserId int
type User struct {
ID UserId
Name string
}
// Lens to user ID
idLens := L.MakeLens(
func(u User) UserId { return u.ID },
func(u User, id UserId) User {
u.ID = id
return u
},
)
// Isomorphism: UserId ↔ int
userIdIso := I.MakeIso(
func(id UserId) int { return int(id) },
func(i int) UserId { return UserId(i) },
)
// Compose to work with raw int
idIntLens := F.Pipe1(
idLens,
iso.Compose[User, UserId, int](userIdIso),
)
user := User{ID: 42, Name: "Alice"}
rawId := idIntLens.Get(user) // 42 (int)
updated := idIntLens.Set(100)(user) // UserId(100)
## Nested Nullable Fields
Safely navigate through nullable nested structures:
type Address struct {
Street string
City string
}
type Person struct {
Name string
Address *Address
}
type Company struct {
Name string
CEO *Person
}
// Lens to CEO
ceoLens := L.MakeLens(
func(c Company) *Person { return c.CEO },
func(c Company, p *Person) Company {
c.CEO = p
return c
},
)
// Isomorphism for nullable person
personIso := iso.FromNillable[Person]()
// Compose to work with Option[Person]
ceoOptLens := F.Pipe1(
ceoLens,
iso.Compose[Company, *Person, O.Option[Person]](personIso),
)
company := Company{Name: "Acme Corp", CEO: nil}
ceo := ceoOptLens.Get(company) // None[Person]
// Set CEO
newCEO := Person{Name: "Alice", Address: nil}
updated := ceoOptLens.Set(O.Some(newCEO))(company)
# Composition Patterns
## Chaining Multiple Isomorphisms
type Meters float64
type Kilometers float64
type Miles float64
type Journey struct {
Distance Meters
}
// Lens to distance
distLens := L.MakeLens(
func(j Journey) Meters { return j.Distance },
func(j Journey, d Meters) Journey {
j.Distance = d
return j
},
)
// Isomorphisms
metersToKm := I.MakeIso(
func(m Meters) Kilometers { return Kilometers(m / 1000) },
func(km Kilometers) Meters { return Meters(km * 1000) },
)
kmToMiles := I.MakeIso(
func(km Kilometers) Miles { return Miles(km * 0.621371) },
func(mi Miles) Kilometers { return Kilometers(mi / 0.621371) },
)
// Compose lens with chained isomorphisms
milesLens := F.Pipe2(
distLens,
iso.Compose[Journey, Meters, Kilometers](metersToKm),
iso.Compose[Journey, Kilometers, Miles](kmToMiles),
)
journey := Journey{Distance: 5000} // 5000 meters
miles := milesLens.Get(journey) // ~3.11 miles
## Combining with Optional Lenses
type Config struct {
Database *DatabaseConfig
}
type DatabaseConfig struct {
Port int
}
// Lens to database (nullable)
dbLens := L.MakeLens(
func(c Config) *DatabaseConfig { return c.Database },
func(c Config, db *DatabaseConfig) Config {
c.Database = db
return c
},
)
// Convert to Option lens
dbIso := iso.FromNillable[DatabaseConfig]()
dbOptLens := F.Pipe1(
dbLens,
iso.Compose[Config, *DatabaseConfig, O.Option[DatabaseConfig]](dbIso),
)
// Now compose with lens to port
portLens := L.MakeLens(
func(db DatabaseConfig) int { return db.Port },
func(db DatabaseConfig, port int) DatabaseConfig {
db.Port = port
return db
},
)
// Use ComposeOption to handle the Option
defaultDB := DatabaseConfig{Port: 5432}
configPortLens := F.Pipe1(
dbOptLens,
L.ComposeOption[Config, int](defaultDB)(portLens),
)
# Performance Considerations
Composing lenses with isomorphisms is efficient:
- No additional allocations beyond the lens and iso structures
- Composition creates function closures but is still performant
- The isomorphism transformations are applied on-demand
- Consider caching composed lenses for frequently used paths
# Type Safety
All operations are fully type-safe:
- Compile-time type checking ensures correct composition
- Generic type parameters prevent type mismatches
- No runtime type assertions needed
- The compiler enforces that isomorphisms are properly reversible
# Related Packages
- github.com/IBM/fp-go/v2/optics/lens: Core lens functionality
- github.com/IBM/fp-go/v2/optics/iso: Core isomorphism functionality
- github.com/IBM/fp-go/v2/optics/iso/lens: Convert isomorphisms to lenses
- github.com/IBM/fp-go/v2/option: Option type and operations
- github.com/IBM/fp-go/v2/function: Function composition utilities
# See Also
For more information on lenses and isomorphisms:
- optics/lens package documentation
- optics/iso package documentation
- optics package overview
*/
package iso
// Made with Bob