README
¶
fp-go gen/v2
Code generator for fp-go/v2 — produces lenses and prisms for Go struct types.
Commands
| Command | Purpose |
|---|---|
lens |
Generate lenses and prisms for struct fields |
mcp |
MCP server utilities |
cp |
Copy utilities |
embed |
Embed utilities |
examples |
Examples utilities |
lens — Lens & Prism Generation
Two invocation modes
1. Annotation mode (default)
Add the comment annotation // fp-go:Lens directly above a struct
declaration. Then run the generator against the directory that contains it.
// fp-go:Lens
type Address struct {
Street string
City string
ZipCode string
Tags []string
}
fp-go lens --dir ./mypkg --filename gen_lens.go
2. Type-name mode (--type, stringer-style)
Name the struct explicitly on the command line without modifying the source.
A package pattern (default .) is passed as a positional argument.
This mode uses go/packages for full type resolution — generics, external
field types, and struct tags all work without source annotations.
# Single type in the current package
fp-go lens --type Server --dir ./mypkg --filename gen_lens.go .
# Type from an external package
fp-go lens --type Server --dir ./out net/http
# Multiple types, names read from a file (one per line, # = comment)
fp-go lens --type @types.txt --dir ./mypkg --filename gen_lens.go .
Flags
| Flag | Default | Description |
|---|---|---|
--dir |
. |
Directory to scan / write output to |
--filename |
gen.go |
Name of the generated file |
--type |
(unset) | Comma-separated struct names, or @file |
--package |
(derived) | Package name for the generated file |
--include-test-files / -t |
false |
Include *_test.go files in annotation scan |
--verbose / -v |
false |
Print progress to stderr |
What gets generated
For every annotated (or named) struct, the generator emits three layers of output into the target file:
| Layer | What | Why |
|---|---|---|
| Struct types | <TYPE>Lenses, <TYPE>RefLenses, <TYPE>Prisms, <TYPE>RefPrisms |
Collect all lenses/prisms for a type in one value |
| Standalone functions | Make<TYPE><FIELD>Lens(), Make<TYPE><FIELD>LensO(), Make<TYPE><FIELD>RefLens(), Make<TYPE><FIELD>RefLensO(), Make<TYPE><FIELD>Prism(), Make<TYPE><FIELD>RefPrism() |
Importable one-by-one — the linker only includes what is called |
| Bulk constructors | Make<TYPE>Lenses(), Make<TYPE>RefLenses(), Make<TYPE>Prisms(), Make<TYPE>RefPrisms() |
Convenience: create all lenses/prisms at once; delegate to standalone functions |
Field rules
| Field characteristic | Lens |
LensO |
Ref variant | Prism / RefPrism |
|---|---|---|---|---|
Comparable (e.g. string, int, pointer) |
✓ | ✓ | ✓ (MakeLensStrictWithName) |
✓ (FromNonZero) |
Non-comparable (e.g. []T, map, func) |
✓ | — | ✓ (MakeLensRefWithName) |
✓ (Some) |
Already an option.Option[A] |
✓ | — (would produce Option[Option[A]]) |
✓ | ✓ |
LensO(optional lens) treats the zero value of a field as "absent" (None) and any non-zero value as "present" (Some). It is only generated for comparable field types where the zero/non-zero distinction is meaningful.
Complete example
Input (address.go)
package mypkg
// fp-go:Lens
type Address struct {
Street string
City string
ZipCode string
Tags []string
}
Command
fp-go lens --dir ./mypkg --filename gen_lens.go
Output (gen_lens.go) — verbatim output of the tool
package mypkg
// Code generated by go generate; DO NOT EDIT.
// This file was generated by robots.
import (
__iso_option "github.com/IBM/fp-go/v2/optics/iso/option"
__lens "github.com/IBM/fp-go/v2/optics/lens"
__lens_option "github.com/IBM/fp-go/v2/optics/lens/option"
__prism "github.com/IBM/fp-go/v2/optics/prism"
__option "github.com/IBM/fp-go/v2/option"
)
// AddressLenses provides [lenses] for accessing fields of [Address]
//
// [lenses]: __lens.Lens
type AddressLenses struct {
// Street is a [__lens.Lens] for the Street field of [Address]
Street __lens.Lens[Address, string]
// City is a [__lens.Lens] for the City field of [Address]
City __lens.Lens[Address, string]
// ZipCode is a [__lens.Lens] for the ZipCode field of [Address]
ZipCode __lens.Lens[Address, string]
// Tags is a [__lens.Lens] for the Tags field of [Address]
Tags __lens.Lens[Address, []string]
// StreetO is a [__lens_option.LensO] for the Street field of [Address], treating the zero value as absent
StreetO __lens_option.LensO[Address, string]
// CityO is a [__lens_option.LensO] for the City field of [Address], treating the zero value as absent
CityO __lens_option.LensO[Address, string]
// ZipCodeO is a [__lens_option.LensO] for the ZipCode field of [Address], treating the zero value as absent
ZipCodeO __lens_option.LensO[Address, string]
}
// AddressRefLenses provides [lenses] for accessing fields of [Address] via a pointer to [Address]
//
// [lenses]: __lens.Lens
type AddressRefLenses struct {
// Street is a [__lens.Lens] for the Street field of [Address] via a pointer receiver
Street __lens.Lens[*Address, string]
// City is a [__lens.Lens] for the City field of [Address] via a pointer receiver
City __lens.Lens[*Address, string]
// ZipCode is a [__lens.Lens] for the ZipCode field of [Address] via a pointer receiver
ZipCode __lens.Lens[*Address, string]
// Tags is a [__lens.Lens] for the Tags field of [Address] via a pointer receiver
Tags __lens.Lens[*Address, []string]
// StreetO is a [__lens_option.LensO] for the Street field of [Address] via a pointer receiver, treating the zero value as absent
StreetO __lens_option.LensO[*Address, string]
// CityO is a [__lens_option.LensO] for the City field of [Address] via a pointer receiver, treating the zero value as absent
CityO __lens_option.LensO[*Address, string]
// ZipCodeO is a [__lens_option.LensO] for the ZipCode field of [Address] via a pointer receiver, treating the zero value as absent
ZipCodeO __lens_option.LensO[*Address, string]
}
// AddressPrisms provides [prisms] for accessing fields of [Address]
//
// [prisms]: __prism.Prism
type AddressPrisms struct {
// Street is a [__prism.Prism] for the Street field of [Address]
Street __prism.Prism[Address, string]
// City is a [__prism.Prism] for the City field of [Address]
City __prism.Prism[Address, string]
// ZipCode is a [__prism.Prism] for the ZipCode field of [Address]
ZipCode __prism.Prism[Address, string]
// Tags is a [__prism.Prism] for the Tags field of [Address]
Tags __prism.Prism[Address, []string]
}
// AddressRefPrisms provides [prisms] for accessing fields of [Address] via a pointer to [Address]
//
// [prisms]: __prism.Prism
type AddressRefPrisms struct {
// Street is a [__prism.Prism] for the Street field of [Address] via a pointer receiver
Street __prism.Prism[*Address, string]
// City is a [__prism.Prism] for the City field of [Address] via a pointer receiver
City __prism.Prism[*Address, string]
// ZipCode is a [__prism.Prism] for the ZipCode field of [Address] via a pointer receiver
ZipCode __prism.Prism[*Address, string]
// Tags is a [__prism.Prism] for the Tags field of [Address] via a pointer receiver
Tags __prism.Prism[*Address, []string]
}
// MakeAddressStreetLens returns a [__lens.Lens] for the Street field of [Address]
func MakeAddressStreetLens() __lens.Lens[Address, string] {
return __lens.MakeLensWithName(
func(s Address) string { return s.Street },
func(s Address, v string) Address { s.Street = v; return s },
"Address.Street",
)
}
// MakeAddressStreetLensO returns a [__lens_option.LensO] for the Street field of [Address]
func MakeAddressStreetLensO() __lens_option.LensO[Address, string] {
return __lens_option.FromIso[Address](__iso_option.FromZero[string]())(MakeAddressStreetLens())
}
// MakeAddressStreetRefLens returns a [__lens.Lens] for the Street field of [Address] via a pointer receiver
func MakeAddressStreetRefLens() __lens.Lens[*Address, string] {
return __lens.MakeLensStrictWithName(
func(s *Address) string { return s.Street },
func(s *Address, v string) *Address { s.Street = v; return s },
"(*Address).Street",
)
}
// MakeAddressStreetRefLensO returns a [__lens_option.LensO] for the Street field of [Address] via a pointer receiver
func MakeAddressStreetRefLensO() __lens_option.LensO[*Address, string] {
return __lens_option.FromIso[*Address](__iso_option.FromZero[string]())(MakeAddressStreetRefLens())
}
// MakeAddressStreetPrism returns a [__prism.Prism] for the Street field of [Address]
func MakeAddressStreetPrism() __prism.Prism[Address, string] {
_fromNonZero := __option.FromNonZero[string]()
return __prism.MakePrismWithName(
func(s Address) __option.Option[string] { return _fromNonZero(s.Street) },
func(v string) Address {
return Address{Street: v}
},
"Address.Street",
)
}
// MakeAddressStreetRefPrism returns a [__prism.Prism] for the Street field of [Address] via a pointer receiver
func MakeAddressStreetRefPrism() __prism.Prism[*Address, string] {
_fromNonZero := __option.FromNonZero[string]()
return __prism.MakePrismWithName(
func(s *Address) __option.Option[string] { return _fromNonZero(s.Street) },
func(v string) *Address {
return &Address{Street: v}
},
"(*Address).Street",
)
}
// MakeAddressCityLens returns a [__lens.Lens] for the City field of [Address]
// MakeAddressCityLensO, MakeAddressCityRefLens, MakeAddressCityRefLensO,
// MakeAddressCityPrism, MakeAddressCityRefPrism — identical pattern to Street.
// MakeAddressZipCodeLens, …ZipCodeLensO, …ZipCodeRefLens, …ZipCodeRefLensO,
// …ZipCodePrism, …ZipCodeRefPrism — identical pattern to Street.
// MakeAddressTagsLens returns a [__lens.Lens] for the Tags field of [Address]
func MakeAddressTagsLens() __lens.Lens[Address, []string] {
return __lens.MakeLensWithName(
func(s Address) []string { return s.Tags },
func(s Address, v []string) Address { s.Tags = v; return s },
"Address.Tags",
)
}
// MakeAddressTagsRefLens returns a [__lens.Lens] for the Tags field of [Address] via a pointer receiver
func MakeAddressTagsRefLens() __lens.Lens[*Address, []string] {
return __lens.MakeLensRefWithName( // []string is not comparable → MakeLensRefWithName
func(s *Address) []string { return s.Tags },
func(s *Address, v []string) *Address { s.Tags = v; return s },
"(*Address).Tags",
)
}
// MakeAddressTagsPrism returns a [__prism.Prism] for the Tags field of [Address]
func MakeAddressTagsPrism() __prism.Prism[Address, []string] {
return __prism.MakePrismWithName(
func(s Address) __option.Option[[]string] { return __option.Some(s.Tags) }, // not comparable → Some
func(v []string) Address {
return Address{Tags: v}
},
"Address.Tags",
)
}
// MakeAddressTagsRefPrism returns a [__prism.Prism] for the Tags field of [Address] via a pointer receiver
func MakeAddressTagsRefPrism() __prism.Prism[*Address, []string] {
return __prism.MakePrismWithName(
func(s *Address) __option.Option[[]string] { return __option.Some(s.Tags) },
func(v []string) *Address {
return &Address{Tags: v}
},
"(*Address).Tags",
)
}
// MakeAddressLenses creates a new [AddressLenses] with [lenses] for all fields
//
// [lenses]: __lens.Lens
func MakeAddressLenses() AddressLenses {
return AddressLenses{
// mandatory lenses
Street: MakeAddressStreetLens(),
City: MakeAddressCityLens(),
ZipCode: MakeAddressZipCodeLens(),
Tags: MakeAddressTagsLens(),
// optional lenses
StreetO: MakeAddressStreetLensO(),
CityO: MakeAddressCityLensO(),
ZipCodeO: MakeAddressZipCodeLensO(),
}
}
// MakeAddressRefLenses creates a new [AddressRefLenses] with [lenses] for all fields via a pointer to [Address]
//
// [lenses]: __lens.Lens
func MakeAddressRefLenses() AddressRefLenses {
return AddressRefLenses{
// mandatory lenses
Street: MakeAddressStreetRefLens(),
City: MakeAddressCityRefLens(),
ZipCode: MakeAddressZipCodeRefLens(),
Tags: MakeAddressTagsRefLens(),
// optional lenses
StreetO: MakeAddressStreetRefLensO(),
CityO: MakeAddressCityRefLensO(),
ZipCodeO: MakeAddressZipCodeRefLensO(),
}
}
// MakeAddressPrisms creates a new [AddressPrisms] with [prisms] for all fields
//
// [prisms]: __prism.Prism
func MakeAddressPrisms() AddressPrisms {
return AddressPrisms{
Street: MakeAddressStreetPrism(),
City: MakeAddressCityPrism(),
ZipCode: MakeAddressZipCodePrism(),
Tags: MakeAddressTagsPrism(),
}
}
// MakeAddressRefPrisms creates a new [AddressRefPrisms] with [prisms] for all fields via a pointer to [Address]
//
// [prisms]: __prism.Prism
func MakeAddressRefPrisms() AddressRefPrisms {
return AddressRefPrisms{
Street: MakeAddressStreetRefPrism(),
City: MakeAddressCityRefPrism(),
ZipCode: MakeAddressZipCodeRefPrism(),
Tags: MakeAddressTagsRefPrism(),
}
}
The City and ZipCode blocks are abridged with a comment — the real file contains the full six-function set for every field, identical to the Street pattern shown above.
Naming conventions
| Generated symbol | Pattern | Example |
|---|---|---|
| Struct type — value lenses | <TYPE>Lenses |
AddressLenses |
| Struct type — pointer lenses | <TYPE>RefLenses |
AddressRefLenses |
| Struct type — value prisms | <TYPE>Prisms |
AddressPrisms |
| Struct type — pointer prisms | <TYPE>RefPrisms |
AddressRefPrisms |
| Standalone value lens | Make<TYPE><FIELD>Lens() |
MakeAddressStreetLens() |
| Standalone optional value lens | Make<TYPE><FIELD>LensO() |
MakeAddressStreetLensO() |
| Standalone pointer lens | Make<TYPE><FIELD>RefLens() |
MakeAddressStreetRefLens() |
| Standalone optional pointer lens | Make<TYPE><FIELD>RefLensO() |
MakeAddressStreetRefLensO() |
| Standalone value prism | Make<TYPE><FIELD>Prism() |
MakeAddressStreetPrism() |
| Standalone pointer prism | Make<TYPE><FIELD>RefPrism() |
MakeAddressStreetRefPrism() |
| Bulk value lens constructor | Make<TYPE>Lenses() |
MakeAddressLenses() |
| Bulk pointer lens constructor | Make<TYPE>RefLenses() |
MakeAddressRefLenses() |
| Bulk value prism constructor | Make<TYPE>Prisms() |
MakeAddressPrisms() |
| Bulk pointer prism constructor | Make<TYPE>RefPrisms() |
MakeAddressRefPrisms() |
Binary-size note
The bulk constructors (Make<TYPE>Lenses() etc.) are convenient but pull in
every field's lens/prism. If only a subset of fields is needed at a given
call site, call the standalone functions directly — the Go linker will
tree-shake the unused ones and produce a smaller binary.
// Only the Street lens is linked:
streetLens := MakeAddressStreetLens()
// All lenses are linked:
lenses := MakeAddressLenses()
Generic structs
Generic structs are fully supported. Type parameters are preserved in every generated symbol:
// fp-go:Lens
type Box[T any] struct {
Content T
Label string
}
Generates (among others):
func MakeBoxContentLens[T any]() __lens.Lens[Box[T], T] { … }
func MakeBoxLabelLensO[T any]() __lens_option.LensO[Box[T], string] { … }
func MakeBoxLenses[T any]() BoxLenses[T] { … }
ContentO/ContentRefLensOare not generated when the type parameter is constrained byany(not comparable). They are generated when constrained bycomparable.
Embedded structs
Fields promoted from embedded structs are included automatically (one level deep):
type Point struct{ X, Y float64 }
// fp-go:Lens
type Shape struct {
Point // promoted: X and Y appear as fields of Shape
Color string
}
Generates MakeShapeXLens(), MakeShapeYLens(), MakeShapeColorLens(), etc.
go:generate integration
//go:generate fp-go lens --dir . --filename gen_lens.go
Or with the type-name mode (no annotation needed in the source):
//go:generate fp-go lens --type MyStruct --dir . --filename gen_lens.go .