Nicolas Lattuada
07/09/2020, 8:34 AMfun t(dto: UpgradeTrigger) {
UpgradeTrigger.run {
title.modify(dto) { it.toUpperCase() }
subtitle.modify(dto) { it.toUpperCase() }
}
}
Nicolas Lattuada
07/09/2020, 8:38 AMfun t(dto: UpgradeTrigger) {
UpgradeTrigger.run {
val copy = title.modify(dto) { it.toUpperCase() }
subtitle.modify(copy) { it.toUpperCase() }
}
}
Sasha Chepurnoi
07/09/2020, 9:19 AMfun <T> opticsCompose(entity: T, vararg transformations: (T) -> T): T {
return transformations.fold(entity, { e, transformation -> transformation(e) })
}
Then you can use it as:
opticsCompose(template,
{ t -> DocumentTemplate.title.set(t, input.title) },
{ t -> DocumentTemplate.description.set(t, input.description) },
{ t -> DocumentTemplate.template.set(t, input.template) }
)
Nicolas Lattuada
07/09/2020, 9:20 AMNicolas Lattuada
07/09/2020, 9:20 AMsimon.vergauwen
07/09/2020, 9:44 AMLens<UpdateTrigger, Pair<String, String>>
Which would allow you to do
UpdatedTrigger.titleAndSubtitle.modify(dto) { (title, subtitle) -> Pair(title.toUpperCase(), subtitle.toUpperCase()) }
But we currently don't have such a combinator. It shouldn't be too hard to write, and I think this might be a useful addition in Optics in any1 is interested in contributing I'd be happy to help!simon.vergauwen
07/09/2020, 9:45 AMNicolas Lattuada
07/09/2020, 9:53 AMJannis
07/09/2020, 10:37 AMdto
& title %~ toUpper
& subtitle %~ toUpper
& is function application with the arguments reversed (instead of f(a) you have a & f. apply is probably closest to this)
%~ is modify
just reads much nicer. @simon.vergauwen is it possible to return a partially applied function application in the modify function so that this becomes possible? If modify would return (s) -> t
instead of taking s
and returning t
one could write dto.apply(title.modify { it.toUpperCase() }).apply(subtitle.modify { it.toUpperCase() })
Anyway, combining optics works, but avoiding the intermediate copy is not possible afaik. You will always need to invoke the lenses one by one even if you write a combinator
combine :: Lens a b -> Lens a c -> Lens a (b, c)
combine la lb = lens (\c -> (c ^. la, c ^. lb)) (\c (a, b) -> c & la .~ a & lb .~ b)
Sorry for the haskell code, its just what I am most familiar with when it comes to optics :)
Only way I see to avoid that is to manually compose them.
The reason this does not work generally is because a Lens makes no assumption about how the setter side works: Consider two lenses providing virtual fields firstName
and lastName
both backed by the same fullName
field on the object (the lens splits the actual property and provides the first or last name). These two lenses cannot be combined easily as they both operate on the same field and the update semantics are not clear at all. For such a combinator we always need to know how the lens works.
Combining only ever works if either done in sequence (creating intermediate copies) or by hand rolling combined lenses.Jannis
07/09/2020, 10:39 AMfun <T, T1> T.applyF(f: (T) -> T1): T1
simon.vergauwen
07/09/2020, 10:43 AMlift
, right?Jannis
07/09/2020, 10:50 AM&
)simon.vergauwen
07/09/2020, 10:51 AMPlens<S, T, A, B>
it takes (A) -> B
and returns (S) -> T
simon.vergauwen
07/09/2020, 10:52 AMsimon.vergauwen
07/09/2020, 10:52 AMStream(..).map(lens.lift(::mapper))
Jannis
07/09/2020, 10:56 AM&
and you can write:
dto.applyF(title.lift { it.toUpperCase() }).applyF(subtitle.lift { it.toUpperCase() })
Not sure how the structure in arrow-optics works, but is lift
available to all optics or just lenses because it should work for traversals as well right?Jannis
07/09/2020, 10:56 AMsimon.vergauwen
07/09/2020, 10:56 AMsimon.vergauwen
07/09/2020, 10:57 AMsimon.vergauwen
07/09/2020, 10:58 AMJannis
07/09/2020, 11:01 AMsimon.vergauwen
07/09/2020, 11:06 AMJannis
07/09/2020, 11:08 AM