Comments (9)
Ah right, I was inconsistent. In the modify
example the order is switched.
from accessors.jl.
There is an incomplete list of changes here. Some goals were to make lenses more light weight, in particular duck typed and avoid overloading Base.get
.
Can you given an example what kind of Flatten
like thing you would like to do? I think for modification, this package should be quite powerful e.g. replace all orange leaves by red ones in a tree. For actual flattening e.g. collect all orange leaves into a vector, this is currently not supported. And I am not certain what is the best design here. Would be interested in your input.
from accessors.jl.
My main practical use case now is https://github.com/rafaqz/ModelParameters.jl
The main thing missing from Accessors.jl that you can do with Flatten.jl is context about the leaves on the tree that are replaced. What is their parent object, what is the field name, how to call a function of those two things (with fieldname in Val{:fieldname}
for dispatch).
from accessors.jl.
This is most of Flatten.jl I rewrote a while ago for Setfield.jl lenses, with Query
to get values as a tuple and Context
to get information about the values (this is just the get
half).
It does pretty much everything I need. It composes with lenses and mostly has no runtime cost. It could be a separate package ObjectQueries.jl or it could go in Accessors.jl. I'm just not sure how to combine it with Recursive
and Filter
using Setfield
using Setfield: ComposedLens
struct SkipNone end
abstract type Query{S,R} <: Lens end
struct Select{S,R} <: Query{S,R} end
Select{S}() where {S} = Select{S,SkipNone}()
struct Context{X,S,R} <: Query{S,R} end
Context{X,S}() where {X,S} = Context{X,S,SkipNone}()
struct FieldName end
struct ParentObj end
struct ParentType end
@inline query(lens::Select, obj, ::Val{FN}, val) where FN = (val,)
@inline query(lens::ComposedLens, obj, fn::Val{FN}, val) where FN =
(get(query(lens.outer, obj, fn, val)[1], lens.inner),)
@inline query(lens::Context{FieldName}, obj, ::Val{FN}, val) where FN = (FN,)
@inline query(lens::Context{ParentObj}, obj, ::Val{FN}, val) where FN = (obj,)
@inline query(lens::Context{ParentType}, obj, ::Val{FN}, val) where FN = (typeof(obj),)
@inline Setfield.get(obj, lens::Union{ComposedLens{<:Query},Query}) = _get(obj, lens)
@inline Setfield.set(obj, lens::Union{ComposedLens{<:Query},Query}, x) = _set(obj, lens, x)
@generated function _get(obj::O, lens::Union{ComposedLens{<:Query{T,S}},Query{T,S}}
) where {O,T,S}
exp = Expr(:tuple)
for fn in fieldnames(O)
v = quote
fn = $(QuoteNode(fn))
val = getfield(obj, fn)
if val isa T
query(lens, obj, Val{fn}(), val)
elseif !(T isa S)
_get(val, lens)
else
()
end
end
# Splat the result into the output tuple
push!(exp.args, Expr(:..., v))
end
exp
end
using BenchmarkTools
context = Context{FieldName,Real}()
lens = Select{Float64}()
combined = Select{NamedTuple}() ∘ @lens _.b
julia> @btime Setfield.get((7, (a=17.0, b=2.0f0), ("3", 5)), $context)
@btime Setfield.get((7, (a=17.0, b=2.0f0), ("3", 5)), $lens)
2.090 ns (0 allocations: 0 bytes)
(1, :a, :b, 2)
julia> @btime Setfield.get((7, (a=17.0, b=2.0f0), ("3", 5)), $lens)
0.019 ns (0 allocations: 0 bytes)
(17.0,)
julia> @btime Setfield.get((7, (a=17.0, b=2.0f0), ("3", 5)), $combined)
0.019 ns (0 allocations: 0 bytes)
(2.0f0,)
from accessors.jl.
Nice! I really like that this compiles into fast code. Functionlity like this is in scope of Accessors.jl
.
I wonder if we could create an API like this:
optic = @optic _ |> Elements() |> PushCtx() |> _.a |> If(isodd)
obj = [(a=1, b=10), (a=2, b=20), (a=3,b=30)
getall(obj, optic) == [(1, (a=1, b=10)), (3, (a=3, b=30))]
modify(obj, optic) do a, ctx
a + ctx.b
end == [(a=11, b=10), (a=2, b=20), (a=33,b=30)]
So you can specify in your query with PushCtx
how much context is needed.
from accessors.jl.
That's cool! I couldn't think of how context would work and still compose with lenses and have the context pass through, or how set
would work. If I understand this, PushCtx
returns a (context, result)
tuple? So you could add more PushCtx
lenses and just get more deeply nested tuple results? That seems like a good way to do this.
Being really fast is nice for programming style, you can just use the lens result as if that's what the object actually is, without thinking about the lens being there.
from accessors.jl.
That's cool! I couldn't think of how context would work and still compose with lenses and have the context pass through, or how
set
would work. If I understand this,PushCtx
returns a(context, result)
tuple? So you could add morePushCtx
lenses and just get more deeply nested tuple results? That seems like a good way to do this.
Basically yes, with the minor detail that I had (result, context)
instead of (context, result)
in mind. IIRC they have a similar mechnic in the clojure library Specter. I recommend this talk.
Being really fast is nice for programming style, you can just use the lens result as if that's what the object actually is, without thinking about the lens being there.
Yes, I hate if I have to think during programming 😄
from accessors.jl.
Ok cool, I read this as (context, result)
from _.a
and a=1
, a=3
:
getall(obj, optic) == [((a=1, b=10), 1), ((a=3, b=30),3)]
Maybe I misunderstand what getall
is.
from accessors.jl.
Sry the modify example is also wrong, I will edit my post above.
from accessors.jl.
Related Issues (20)
- `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
- AccessorsExtra.jl HOT 1
- `@set` with slices or broadcasting HOT 5
- Set multiple fields HOT 2
- insert not working for stucts? HOT 6
- "Concat lens": combine multiple lenses side by side HOT 7
- Assemble an object from optics HOT 7
- `hasproperty()` analogue for optics HOT 3
- IndexLens and changing the container size 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.