template <typename LensT, typename T>
decltype(auto) lager::view(LensT && lens, T && x)
template <typename LensT, typename T, typename U>
decltype(auto) lager::set(LensT && lens, T && x, U && v)
template <typename LensT, typename T, typename Fn>
decltype(auto) lager::over(LensT && lens, T && x, Fn && fn)
template <typename Whole, typename Part>
class lager::lens
ZUG_INLINE_CONSTEXPR auto lager::lenses::or_default = value_or()

() -> Lens<[X], X>

ZUG_INLINE_CONSTEXPR auto lager::lenses::force_opt = zug::comp([](auto&& f) { return [f = std::forward<decltype( f )>( f )](auto&& p) { using opt_t = std::optional<std::decay_t<decltype(p)>>; return f(opt_t{std::forward<decltype( p )>( p )})( [&](auto&& x) { return std::forward<decltype( x )>( x ).value_or(std::forward<decltype( p )>( p )); }); }; })

Lens<T, [T]>

auto lager::lenses::element = detail::element_t<N>{}

N -> Lens<(P1, …, Pn), PN>

Note: works for pairs, tuples, arrays. don’t use on variants.

auto lager::lenses::first = element<0>
auto lager::lenses::second = element<1>
ZUG_INLINE_CONSTEXPR auto lager::lenses::unbox = zug::comp([](auto&& f) { return [f](auto&& p) { return f(std::forward<decltype( p )>( p ).get())( [&](auto&& x) { return std::decay_t<decltype(p)>{std::forward<decltype( x )>( x )}; }); }; })

Lens<box<T>, T>

auto lager::lenses::alternative = detail::alternative_t<T>{}
template <typename Getter, typename Setter>
auto lager::lenses::getset(Getter &&getter, Setter &&setter)
template <typename Key>
auto lager::lenses::at(Key key)

Key -> Lens<{X}, [X]>

template <typename Member>
auto lager::lenses::attr(Member member)

(Part Whole::*) -> Lens<Whole, Part>

template <typename Lens>
auto lager::lenses::map_opt(Lens &&lens)

Lens<W, P> -> Lens<[W], [P]>

template <typename Lens>
auto lager::lenses::bind_opt(Lens &&lens)

Lens<W, [P]> -> Lens<[W], [P]>

template <typename Lens>
auto lager::lenses::with_opt(Lens &&lens)

(Lens<W, P> | Lens<W, [P]>) -> Lens<[W], [P]>

template <typename T>
auto lager::lenses::value_or(T &&t)

X -> Lens<[X], X>

ZUG_INLINE_CONSTEXPR auto lager::lenses::value_or()

() -> Lens<[X], X>

template <typename… Lenses>
auto lager::lenses::zip(Lenses&&... lenses)

Lens<W1, P1>, …, Lens<Wn, Pn> -> Lens<(W1, …, Wn), (P1, …, Pn)>

Note: remember you can use the identity function as the identity lens.

template <typename… Lenses>
auto lager::lenses::fan(Lenses&&... lenses)

Lens<W, P1>, …, Lens<W, Pn> -> Lens<W, (P1, …, Pn)>

Note: parts MUST NOT OVERLAP. if they do the fold will overwrite sequential writes to the part. just don’t do it.

template <typename… Member>
auto lager::lenses::attr(Member... member)

(Part Whole::*)…

-> Lens<Whole, (Part…)>

Note: for the same reason as detailed in fan, the members should be distinct from each other.