S
- the type of the "larger" value for readingT
- the type of the "larger" value for puttingA
- the type of the "smaller" value that is readB
- the type of the "smaller" update value@FunctionalInterface public interface Lens<S,T,A,B> extends Optic<Cartesian<?,?,?>,Functor<?,?>,S,T,A,B>, MonadRec<T,Lens<S,?,A,B>>, Profunctor<S,T,Lens<?,?,A,B>>
A "lens" can be considered in its simplest form as the conjugation of a "getter" and a "setter"; that is, a
unification type representing the way to retrieve a "smaller" value A
from a "larger" value
S
, as well as a way to update a "smaller" value B
of a "larger" value S
,
producing another "larger" value T
.
Consider the following example:
public final class Person {
private final int age;
public Person(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public Person setAge(int age) {
return new Person(age);
}
}
A lens that focused on the age
field of an instance of Person
might look like this:
Lens<Person, Person, Integer, Integer> ageLens = Lens.lens(Person::getAge, Person::setAge);
Person adult = new Person(18);
Integer age = view(ageLens, adult); // 18
Person olderAdult = set(ageLens, 19, adult);
Integer olderAge = view(ageLens, olderAdult); // 19
The pattern of a getter and setter that mutually agree on both A
and B
as well as on both
S
and T
is so common that this can be given a simplified type signature:
Lens.Simple<Person, Integer> ageLens = Lens.simpleLens(Person::getAge, Person::setAge);
Person adult = new Person(18);
Integer age = view(ageLens, adult); // 18
Person olderAdult = set(ageLens, 19, adult);
Integer olderAge = view(ageLens, olderAdult); // 19
However, consider if age
could be updated on a Person
by being provided a date of birth, in
the form of a LocalDate
:
public final class Person {
private final int age;
public Person(int age) {
this.age = age;
}
public int getAge() {
return age;
}
public Person setAge(int age) {
return new Person(age);
}
public Person setAge(LocalDate dob) {
return setAge((int) YEARS.between(dob, LocalDate.now()));
}
}
This is why Lens has both an A
and a B
: A
is the value for "getting", and
B
is the potentially different value for "setting". This distinction makes lenses powerful enough to
express the more complicated setAge
case naturally:
Lens<Person, Person, Integer, LocalDate> ageDobLens = Lens.lens(Person::getAge, Person::setAge);
Person adult = new Person(18);
Integer age = view(ageDobLens, adult); // 18
Person olderAdult = set(ageDobLens, LocalDate.of(1997, 1, 1), adult);
Integer olderAge = view(ageDobLens, olderAdult); // 19 at the time of this writing...anyone else feel old?
Additionally, we might imagine a lens that produces a different "larger" value on updating than what was given.
Consider a lens that reads the first string from a list, but produces a Set of strings on update:
Lens<List<String>, Set<String>, String, String> lens = Lens.lens(
l -> l.get(0),
(l, s) -> {
List<String> copy = new ArrayList<>(l);
copy.set(0, s);
return new HashSet<>(copy);
});
String firstElement = view(lens, asList("foo", "bar")); // "foo
System.out.println(firstElement);
set(lens, "oof", asList("foo", "bar")); // ["bar", "oof"]
set(lens, "bar", asList("foo", "bar")); // ["bar"]
For more information, learn
about
lenses.Modifier and Type | Interface and Description |
---|---|
static interface |
Lens.Simple<S,A>
A convenience type with a simplified type signature for common lenses with both unified "larger" values and
unified "smaller" values.
|
Modifier and Type | Method and Description |
---|---|
default <C,D> Lens<S,T,C,D> |
andThen(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,A,B,C,D> f)
Left-to-right composition of optics.
|
static <S,A,B> Lens.Simple<S,Tuple2<A,B>> |
both(Lens.Simple<S,A> f,
Lens.Simple<S,B> g)
Dually focus on two simple lenses at the same time.
|
static <S,A,B,C,D> |
both(Lens<S,S,A,C> f,
Lens<S,S,B,D> g)
Dually focus on two lenses at the same time.
|
default <R,U> Lens<R,U,A,B> |
compose(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,R,U,S,T> g)
Right-to-Left composition of optics.
|
default <R> Lens<R,T,A,B> |
contraMap(Fn1<? super R,? extends S> fn)
Contravariantly map
A <- B . |
default <R,U> Lens<R,U,A,B> |
diMap(Fn1<? super R,? extends S> lFn,
Fn1<? super T,? extends U> rFn)
Dually map contravariantly over the left parameter and covariantly over the right parameter.
|
default <R> Lens<R,T,A,B> |
diMapL(Fn1<? super R,? extends S> fn)
Contravariantly map over the left parameter.
|
default <U> Lens<S,U,A,B> |
diMapR(Fn1<? super T,? extends U> fn)
Covariantly map over the right parameter.
|
default <U> Lens<S,U,A,B> |
discardL(Applicative<U,Lens<S,?,A,B>> appB)
Sequence both this
Applicative and appB , discarding this Applicative's
result and returning appB . |
default <U> Lens<S,T,A,B> |
discardR(Applicative<U,Lens<S,?,A,B>> appB)
Sequence both this
Applicative and appB , discarding appB's result and
returning this Applicative . |
default <U> Lens<S,U,A,B> |
flatMap(Fn1<? super T,? extends Monad<U,Lens<S,?,A,B>>> f)
Chain dependent computations that may continue or short-circuit based on previous results.
|
default <U> Lens<S,U,A,B> |
fmap(Fn1<? super T,? extends U> fn)
Covariantly transmute this functor's parameter using the given mapping function.
|
static <S,T,A,B> Lens<S,T,A,B> |
lens(Fn1<? super S,? extends A> getter,
Fn2<? super S,? super B,? extends T> setter)
Static factory method for creating a lens from a getter function and a setter function.
|
static <S,T,A,B> Lens<S,T,A,B> |
lens(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,S,T,A,B> optic)
Promote an optic with compatible bounds to a
Lens . |
default <C> Lens<S,T,C,B> |
mapA(Fn1<? super A,? extends C> fn)
Covariantly map
A to C , yielding a new optic. |
default <Z> Lens<S,T,A,Z> |
mapB(Fn1<? super Z,? extends B> fn)
Contravariantly map
B to Z , yielding a new optic. |
default <R> Lens<R,T,A,B> |
mapS(Fn1<? super R,? extends S> fn)
Contravariantly map
S to R , yielding a new optic. |
default <U> Lens<S,U,A,B> |
mapT(Fn1<? super T,? extends U> fn)
Covariantly map
T to U , yielding a new optic. |
default <U> Lens<S,U,A,B> |
pure(U u)
Lift the value
b into this applicative functor. |
static <S,A,B> Pure<Lens<S,?,A,B>> |
pureLens(Fn1<? super S,? extends A> sa)
|
static <S,A> Lens.Simple<S,A> |
simpleLens(Fn1<? super S,? extends A> getter,
Fn2<? super S,? super A,? extends S> setter)
Static factory method for creating a simple lens from a getter function and a setter function.
|
default Iso<S,T,A,B> |
toIso(S s)
|
default <U> Lens<S,U,A,B> |
trampolineM(Fn1<? super T,? extends MonadRec<RecursiveResult<T,U>,Lens<S,?,A,B>>> fn)
Given some operation yielding a
RecursiveResult inside this MonadRec , internally trampoline the
operation until it yields a termination instruction. |
default <U> Lens<S,U,A,B> |
zip(Applicative<Fn1<? super T,? extends U>,Lens<S,?,A,B>> appFn)
Given another instance of this applicative over a mapping function, "zip" the two instances together using
whatever application semantics the current applicative supports.
|
apply, monomorphize, optic, reframe
default <U> Lens<S,U,A,B> fmap(Fn1<? super T,? extends U> fn)
fmap
in interface Applicative<T,Lens<S,?,A,B>>
fmap
in interface Functor<T,Lens<S,?,A,B>>
fmap
in interface Monad<T,Lens<S,?,A,B>>
fmap
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the new parameter typefn
- the mapping functiondefault <U> Lens<S,U,A,B> pure(U u)
b
into this applicative functor.pure
in interface Applicative<T,Lens<S,?,A,B>>
pure
in interface Monad<T,Lens<S,?,A,B>>
pure
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the type of the returned applicative's parameteru
- the valuedefault <U> Lens<S,U,A,B> zip(Applicative<Fn1<? super T,? extends U>,Lens<S,?,A,B>> appFn)
zip
in interface Applicative<T,Lens<S,?,A,B>>
zip
in interface Monad<T,Lens<S,?,A,B>>
zip
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the resulting applicative parameter typeappFn
- the other applicative instancedefault <U> Lens<S,U,A,B> discardL(Applicative<U,Lens<S,?,A,B>> appB)
Applicative
and appB
, discarding this Applicative's
result and returning appB
. This is generally useful for sequentially performing side-effects.discardL
in interface Applicative<T,Lens<S,?,A,B>>
discardL
in interface Monad<T,Lens<S,?,A,B>>
discardL
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the type of the returned Applicative's parameterappB
- the other Applicativedefault <U> Lens<S,T,A,B> discardR(Applicative<U,Lens<S,?,A,B>> appB)
Applicative
and appB
, discarding appB's
result and
returning this Applicative
. This is generally useful for sequentially performing side-effects.discardR
in interface Applicative<T,Lens<S,?,A,B>>
discardR
in interface Monad<T,Lens<S,?,A,B>>
discardR
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the type of appB's parameterappB
- the other Applicativedefault <U> Lens<S,U,A,B> flatMap(Fn1<? super T,? extends Monad<U,Lens<S,?,A,B>>> f)
default <U> Lens<S,U,A,B> trampolineM(Fn1<? super T,? extends MonadRec<RecursiveResult<T,U>,Lens<S,?,A,B>>> fn)
RecursiveResult
inside this MonadRec
, internally trampoline the
operation until it yields a termination
instruction.
Stack-safety depends on implementations guaranteeing that the growth of the call stack is a constant factor independent of the number of invocations of the operation. For various examples of how this can be achieved in stereotypical circumstances, see the referenced types.
trampolineM
in interface MonadRec<T,Lens<S,?,A,B>>
U
- the ultimate resulting carrier typefn
- the function to internally trampolineMonadRec
for a basic implementation
,
for a {@link CoProduct2 coproduct} implementation
,
for an implementation leveraging an already stack-safe {@link Monad#flatMap(Fn1)}
,
for a {@link MonadT monad transformer} implementation
default <R> Lens<R,T,A,B> diMapL(Fn1<? super R,? extends S> fn)
default <U> Lens<S,U,A,B> diMapR(Fn1<? super T,? extends U> fn)
diMapR(f) == fmap(f)
.default <R,U> Lens<R,U,A,B> diMap(Fn1<? super R,? extends S> lFn, Fn1<? super T,? extends U> rFn)
diMapL(lFn).diMapR(rFn)
.diMap
in interface Profunctor<S,T,Lens<?,?,A,B>>
R
- the new left parameter typeU
- the new right parameter typelFn
- the left parameter mapping functionrFn
- the right parameter mapping functiondefault <R> Lens<R,T,A,B> contraMap(Fn1<? super R,? extends S> fn)
A <- B
.contraMap
in interface Contravariant<S,Profunctor<?,T,Lens<?,?,A,B>>>
contraMap
in interface Profunctor<S,T,Lens<?,?,A,B>>
R
- the new parameter typefn
- the mapping functiondefault <R> Lens<R,T,A,B> mapS(Fn1<? super R,? extends S> fn)
S
to R
, yielding a new optic.default <U> Lens<S,U,A,B> mapT(Fn1<? super T,? extends U> fn)
T
to U
, yielding a new optic.default <C> Lens<S,T,C,B> mapA(Fn1<? super A,? extends C> fn)
A
to C
, yielding a new optic.default <Z> Lens<S,T,A,Z> mapB(Fn1<? super Z,? extends B> fn)
B
to Z
, yielding a new optic.default <C,D> Lens<S,T,C,D> andThen(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,A,B,C,D> f)
S
and T
.default <R,U> Lens<R,U,A,B> compose(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,R,U,S,T> g)
A
and B
.static <S,T,A,B> Lens<S,T,A,B> lens(Fn1<? super S,? extends A> getter, Fn2<? super S,? super B,? extends T> setter)
S
- the type of the "larger" value for readingT
- the type of the "larger" value for puttingA
- the type of the "smaller" value that is readB
- the type of the "smaller" update valuegetter
- the getter functionsetter
- the setter functionstatic <S,T,A,B> Lens<S,T,A,B> lens(Optic<? super Cartesian<?,?,?>,? super Functor<?,?>,S,T,A,B> optic)
Lens
.static <S,A> Lens.Simple<S,A> simpleLens(Fn1<? super S,? extends A> getter, Fn2<? super S,? super A,? extends S> setter)
S
- the type of both "larger" valuesA
- the type of both "smaller" valuesgetter
- the getter functionsetter
- the setter functionstatic <S,A,B,C,D> Lens<S,S,Tuple2<A,B>,Tuple2<C,D>> both(Lens<S,S,A,C> f, Lens<S,S,B,D> g)
S
and T
to be invariant between
lenses.S
- both larger valuesA
- f's smaller viewing valueB
- g's smaller viewing valueC
- f's smaller setting valueD
- g's smaller setting valuef
- the first lensg
- the second lensstatic <S,A,B> Lens.Simple<S,Tuple2<A,B>> both(Lens.Simple<S,A> f, Lens.Simple<S,B> g)
S
- both larger valuesA
- both smaller viewing valuesB
- both smaller setting valuesf
- the first lensg
- the second lensstatic <S,A,B> Pure<Lens<S,?,A,B>> pureLens(Fn1<? super S,? extends A> sa)
S
- the type of the "larger" value for readingA
- the type of the "smaller" value that is readB
- the type of the "smaller" update valuesa
- the getting functionPure
instance