GithubHelp home page GithubHelp logo

Comments (9)

jw3126 avatar jw3126 commented on May 24, 2024 1

Ah right, I was inconsistent. In the modifyexample the order is switched.

from accessors.jl.

jw3126 avatar jw3126 commented on May 24, 2024

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.

rafaqz avatar rafaqz commented on May 24, 2024

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.

rafaqz avatar rafaqz commented on May 24, 2024

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.

jw3126 avatar jw3126 commented on May 24, 2024

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.

rafaqz avatar rafaqz commented on May 24, 2024

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.

jw3126 avatar jw3126 commented on May 24, 2024

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.

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.

rafaqz avatar rafaqz commented on May 24, 2024

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.

jw3126 avatar jw3126 commented on May 24, 2024

Sry the modify example is also wrong, I will edit my post above.

from accessors.jl.

Related Issues (20)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.