-
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
Leaves
optic
#14
Comments
Nice! Accessing the leaves of a tree is certainly an important task. As I understand, this assumes that the tree structure is encoded using ["some", ["tree", [["encoded", "using"], "vectors"] Is there a way to let the user supply the tree structure? |
Hmm, good question. It's not clear to me in this case even what we'd want the result to look like. Julia infers the type as OTOH, if we instead had some nested structs, that should be manageable. StructArrays has some nice tricks for recasting a struct as a named tuple, and after that it reduces to the previous case. My interest here was to just work with the part that can be manipulated very quickly. So one approach could be to use this as an "outer optic" and pass to something else for each resolved component. Then I guess part of the question is whether the current results should be considered "leaves". Maybe |
I would expect bad performance in this case, but the semantics would be: tree = ["some", ["tree", [["encoded", "using"], "vectors"]
modify(uppercase, tree, Leaves(...)) == ["SOME", ["TREE", [["ENCODED", "USING"], "VECTORS"] My point was that there are many ways trees are encoded and instead of only supporting one somewhat arbitrary way (descent into
I think Recursive goes in this direction. Let's hope inference can handle it 😄 |
using Accessors
x = (a = [1, 2], b = (c = ([3, 4], [5, 6]), d = [7, 8]));
optic = Recursive(x -> x isa Union{Tuple, NamedTuple}, Elements())
@test modify(sum, x, optic, ) === (a = 3, b = (c = (7, 11), d = 15)) But sadly @code_warntype modify(sum, x, optic, )
Variables
#self#::Core.Compiler.Const(Accessors.modify, false)
f::Core.Compiler.Const(sum, false)
obj::NamedTuple{(:a, :b),Tuple{Array{Int64,1},NamedTuple{(:c, :d),Tuple{Tuple{Array{Int64,1},Array{Int64,1}},Array{Int64,1}}}}}
optic::Core.Compiler.Const(Recursive{var"#3#4",Elements}(var"#3#4"(), Elements()), false)
Body::NamedTuple{(:a, :b),_A} where _A<:Tuple
1 ─ nothing
│ %2 = Accessors.OpticStyle(optic)::Core.Compiler.Const(Accessors.ModifyBased(), false)
│ %3 = Accessors._modify(f, obj, optic, %2)::NamedTuple{(:a, :b),_A} where _A<:Tuple
└── return %3
|
Yeah, the reason I started down this path was that statically-typed things should have better performance than I was able to get out of |
You may find julia> x = (a = (1, 2), b = (c = ((3, 4), (5, 6)), d = (7, 8)));
julia> o = RecursiveOfType(Tuple{Vararg{Number}})
julia> @btime modify($sum, $x, $o)
2.903 ns (0 allocations: 0 bytes)
(a = 3, b = (c = (7, 11), d = 15))
julia> @btime getall($x, $o)
3.272 ns (0 allocations: 0 bytes)
((1, 2), (3, 4), (5, 6), (7, 8)) |
@jw3126 I think this is working well now. What do you think of moving
Leaves
into Accessors? It's very fast, and seems it could be useful for others.Most of the code is here. Biggest concern I could see is that it depends on GeneralizedGenerated. There may be a way to drop that dependency, but it would take some fiddling.
It's no trouble to me either way, and I won't be offended if you don't think it's a good fit. Just seems more natural to me to have it in Accessors.
The text was updated successfully, but these errors were encountered: