Comments (7)
One way to implement something like this would be as follows:
example(::Type{<:Complex}) = 0 + 0im
example(::Type{<:Gaussian}) = ...
and then @assemble Gaussian A(_) = 1, fwhm(_) = 1
will expand to
obj = example(Gaussian)
obj = @set A(obj) = 1
obj = @set fwhm(obj) = 1
The disadvantages of this approach would be that it is tricky to make it work for Vector, Tuple, Set...
. Also
it is only a sane operation, if alle the specified lenses commute and give a complete description of an object.
Performance might also be bad in some cases.
Advantages would be that it works for any lenses and any combination of lenses. It does not make defining new lenses any harder.
from accessors.jl.
Sometimes it's not possible to define a setter for a function, but it still can participate in assembly. For example, which parameter should @set area(gaussian) = 1
change - size or amplitude? But assembly from a size and area is unambiguous.
Potentially,
obj = example(Gaussian)
obj = @set A(obj) = 1
obj = @set fwhm(obj) = 1
could be a fallback @assembly
implementation, but I think it is error-prone: very easy to provide a dependent/inconsistent/incomplete set of optics, and get no error.
I imagine a separate function that needs to be overloaded explicitly, like
assemble(::Type{Gaussian}, ::Pair{typeof(area)}, ::Pair{typeof(fwhm)})
So, only specific optic combinations would be supported, that are correct and unambiguous.
Usage of this function interface without @assemble
macro:
assemble(Gaussian, area => 1, fwhm => 2)
assemble(NamedTuple, PropertyLens(:a) => assemble(...), PropertyLens(:b) => assemble(...))
Tangentially to @assemble
, a feature like set g.size so that area(g) = 10
would also be useful sometimes...
from accessors.jl.
I think a good alternative would be to just define some constructors using say KeywordDispatch.jl.
I think the composability of lenses is not very useful here, so keywords are a simpler solution I would personally prefer
@kwdispatch Gaussian()
@kwmethod Gaussian(;A, area) = ...
@kwmethod Gaussian(;A, fwhm) = ...
@kwmethod Gaussian(;area, fwhm) = ...
Although this does not work well with types you don't own like Complex
. If this is important another way would be:
@kwdispatch assemble(::Type{Complex})
@kwmethod(::Type{Complex};real, imag)
@kwmethod(::Type{Complex};polar, abs)
from accessors.jl.
I think the composability of lenses is not very useful here
Totally agree, I also noticed that!
keywords are a simpler solution I would personally prefer
Keywords are indeed conceptually simpler, even when using an extra "magic" package for dispatch.
However, with optics you can also do more advanced assembly, like
@assemble PowerLawSpectrum flux(_, 5u"GHz") = 1u"Jy", flux(_, 10u"GHz") = 0.5u"Jy"
When one has a hammer, everything looks suspiciously like nails :)
Anyway, this assembly
function doesn't need to be in Accessors
because it's only loosely related with primary lens usage patterns. Even more, it's likely better to separate less-stable stuff not to hinder future development. I think, I'll prototype it in AccessorsExtra
at some point, and see over time if it's actually useful.
from accessors.jl.
This function is now available under the name construct
in AccessorsExtra. Optic composability doesn't bring much here indeed, but still I find this interface useful for constructing complex structs.
from accessors.jl.
Just a small update after some time using and extending this construct
functionality. I find it quite useful, even in a wider range of situations than expected.
Highlights:
- Original goal, simply as an interface to construct complicated structs with multiple alternative sets of required parameters. Type author needs to define each combination separately, and then stuff like this works:
construct(Gaussian, area => 1, fwhm => 2)
construct(PowerLawSpectrum, (@o flux(_, 5u"GHz")) => 1u"Jy", (@o flux(_, 10u"GHz")) = 0.5u"Jy")
- Invertible functions can be composed freely, they are automatically handled by the
construct
machinery. Actual examples:
julia> construct(NamedTuple, (@o _.a) => 2, (@o log10(_.b)) => 3)
(a = 2, b = 1000.0)
julia> construct(Complex, abs => 3, rad2deg ∘ angle => 45)
2.121320343559643 + 2.1213203435596424im
- For some common cases, default types are defined so that this works without manually specifying types – and works recursively:
julia> construct((@o _[1]) => 2, (@o log10(_[2])) => 3)
(2, 1000.0)
julia> construct((@o _.a) => 2, (@o log10(_.b)) => 3)
(a = 2, b = 1000.0)
julia> construct((@o _[1].a) => 2, (@o log10(_[2].b)) => 3, (@o _[2].c) => "")
((a = 2,), (b = 1000.0, c = ""))
This actually works as a right inverse for supported optics:
julia> rinverse(f) = x -> construct(f => x)
julia> rinverse(@o _.a)(5)
(a = 5,)
julia> rinverse(@o log10(_.a))(2)
(a = 100.0,)
Together, these features make construct
very nice when one specifies optics and their target values, but manually creating a "base" object (that would work with set()
) is not convenient. For example, in AccessibleOptimization
, one defines the optimization parameters like
OptArgs(
(@o _.comps[1].shift) => 0..10.,
(@o _.comps[1].scale) => 0.3..10.,
...
)
and then can provide a "base" object or omit it. If omitted, construct()
is used, otherwise regular set()
calls.
So, function composability turned out to be actually relevant for construct
as well (I didn't really expect that). But yeah this is probably a more niche case than those targeted by Accessors
itself.
from accessors.jl.
Thanks a lot for the update!
from accessors.jl.
Related Issues (20)
- "Concat lens": combine multiple lenses side by side HOT 7
- `hasproperty()` analogue for optics HOT 3
- IndexLens and changing the container size HOT 3
- `Base.show` ambiguity
- @reset naming convention HOT 4
- fate of insert and delete after these functions get into Base
- How to @reset when the field is known only by its equivalent symbol. HOT 2
- Only a single function argument can be the optic target HOT 3
- [Feature request] Set multiple fields at once HOT 6
- Errors in extensions during precompilation HOT 5
- multi-argument modify HOT 4
- `set` for `StructArray`
- Bad idea, would avoid using this pkg HOT 14
- To be or not to be HOT 3
- Traversal order of `Recursive` HOT 11
- `==` not defined for `IndexLens` HOT 4
- String properties not supported HOT 3
- Tests fail on 1.11 HOT 2
- `@(re)set` very slow when a parametric inner constructor is defined? HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from accessors.jl.