-
Notifications
You must be signed in to change notification settings - Fork 19
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
support two-argument functions in optics #45
Conversation
Thanks for @aplavin for exploring this direction, looks interesting!
So the |
A few usecases I have in mind: Suppose there is a function that modifies the value located by an optic:
Then, one can call it like
Some of these examples require defining corresponding |
Thanks, @aplavin that makes sense to me. In code like |
This should work or not work exactly as before - seems like |
Indeed, it can. I agree that
But that becomes orthogonal to this PR. |
Ok, I am still not 100% convinced, but we can give it a shot. I also have quite some use cases, in the spirit of stripping units or adjusing scale. But usually, these cases are more complex and would not benefit from this PR. What I need from time to time is flatten parts of a nested struct into a rescaled vector that conforms some optimization API. In these cases and I define a custom optic directly.
|
BTW I just checked: julia> using Accessors
julia> a = 1
1
julia> b = 2
2
julia> c = 3
3
julia> @set a*b = c
3 This is somewhat surprising. This happens because julia> @macroexpand @set a*b = c
:(var"#2###_#275" = (Accessors.set)(a * b, (identity)((Accessors.opticcompose)()), begin
#= REPL[6]:1 =#
c
end)) I consider it a bug and if your PR incidentally turns it into an error, that's fine. |
That totally works for me! |
Do you have any neat or simple examples? I'm not really experienced with custom optics, outside of defining |
My code looks close to your code, with one addition. I often need constraint optimization and I often incorportate the constraints by transforming my variables. For instance, say I want to minimize struct Stretch{T}; lo::T; hi::T; end
(o::Stretch)(x_bounded) = # use bijection from [lo, hi] to IR
Accessors.set(_, optic::Stretch, y_unbound) = # use inverse bijection
function optimize(f, obj0, lens)
v0 = lens(obj0)
function _f(v)
obj = set(obj0, lens, v)
f(obj)
end
_sol = LibThatExpectsVectors.optimize(_f, v0)
set(obj0, lens, _sol)
end
optimize(f, 0.5, Stretch(0,1)) Then I build more complicated optics from such building blocks, similar to your code above. |
First I thought that it's better to add more lenses in the same PR, but now I believe it's best to merge this as is. There is one example and a test, confirming that the new machinery works fine. I think I'm going to propose new lenses separately, so that potential discussions of what to include don't affect the two-argument function parsing itself.
For example, this lets to define a stretch (sigmoid) optic directly:
|
This PR doesn't do anything against the case you mentioned. Furthermore, the current behavior is not that unexpected sometimes, and even tested in the testsuite: Accessors.jl/test/test_core.jl Line 123 in fb8fb82
Still not sure if I like this or not, but it's not always a bug. |
Yes it is not the job of the PR to address this, sorry if I made that impression. It was just that if this PR broke that behavior, that would be ok to me.
Yes this was intended in ancient times, where we had no function lenses. But now I think it is a misfeature and I am happy to sacrifice it. Can you add a test, that simulates a user defining |
While we are at it, what do you think of making
Added! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks a lot LGTM. Shall I merge?
Yeah! Please register as well. |
support two-argument functions in optics
It's not "a few" month, but still :)
Flattening turned out to be kinda orthogonal to this PR, and as you surely know it's And indeed arithmetic lenses (many of which are Base.Fix1/2) are especially nice with "flattening". Changing scales, units, doing other transformation to optimization parameters - everything is so composable. |
For now, contains implementation and a single specific
delete
method as an example.If others agree this extension is a good idea, will add more methods and tests.