From 2b36ef517aaf5bc85db850b168b307664f23f617 Mon Sep 17 00:00:00 2001 From: Carlo Lucibello Date: Tue, 29 Nov 2022 09:18:36 +0100 Subject: [PATCH 1/5] add `@leaf` macro --- src/Functors.jl | 16 ++++++++-------- src/functor.jl | 19 ++++++++++++++++--- test/basics.jl | 13 ++++++++++++- 3 files changed, 36 insertions(+), 12 deletions(-) diff --git a/src/Functors.jl b/src/Functors.jl index e5672fe..ca04dfd 100644 --- a/src/Functors.jl +++ b/src/Functors.jl @@ -282,26 +282,26 @@ julia> struct Bar; x; end julia> @functor Bar -julia> struct NoChildren; x; y; end +julia> struct TypeWithNoChildren; x; y; end -julia> m = Foo(Bar([1,2,3]), NoChildren(:a, :b)) -Foo(Bar([1, 2, 3]), NoChildren(:a, :b)) +julia> m = Foo(Bar([1,2,3]), TypeWithNoChildren(:a, :b)) +Foo(Bar([1, 2, 3]), TypeWithNoChildren(:a, :b)) julia> fcollect(m) 4-element Vector{Any}: - Foo(Bar([1, 2, 3]), NoChildren(:a, :b)) + Foo(Bar([1, 2, 3]), TypeWithNoChildren(:a, :b)) Bar([1, 2, 3]) [1, 2, 3] - NoChildren(:a, :b) + TypeWithNoChildren(:a, :b) julia> fcollect(m, exclude = v -> v isa Bar) 2-element Vector{Any}: - Foo(Bar([1, 2, 3]), NoChildren(:a, :b)) - NoChildren(:a, :b) + Foo(Bar([1, 2, 3]), TypeWithNoChildren(:a, :b)) + TypeWithNoChildren(:a, :b) julia> fcollect(m, exclude = v -> Functors.isleaf(v)) 2-element Vector{Any}: - Foo(Bar([1, 2, 3]), NoChildren(:a, :b)) + Foo(Bar([1, 2, 3]), TypeWithNoChildren(:a, :b)) Bar([1, 2, 3]) ``` """ diff --git a/src/functor.jl b/src/functor.jl index 65b845e..289c79f 100644 --- a/src/functor.jl +++ b/src/functor.jl @@ -1,5 +1,5 @@ -functor(T, x) = (), _ -> x +@leaf Any functor(x) = functor(typeof(x), x) functor(::Type{<:Tuple}, x) = x, identity @@ -7,7 +7,7 @@ functor(::Type{<:NamedTuple{L}}, x) where L = NamedTuple{L}(map(s -> getproperty functor(::Type{<:Dict}, x) = Dict(k => x[k] for k in keys(x)), identity functor(::Type{<:AbstractArray}, x) = x, identity -functor(::Type{<:AbstractArray{<:Number}}, x) = (), _ -> x +@leaf AbstractArray{<:Number} function makefunctor(m::Module, T, fs = fieldnames(T)) yᵢ = 0 @@ -31,7 +31,20 @@ macro functor(args...) functorm(args...) end -isleaf(@nospecialize(x)) = children(x) === () + +const NoChildren = Tuple{} + +function makeleaf(m::Module, T) + @eval m begin + $Functors.functor(::Type{<:$T}, x) = $Functors.NoChildren(), _ -> x + end +end + +macro leaf(T) + :(makeleaf(@__MODULE__, $(esc(T)))) +end + +isleaf(@nospecialize(x)) = children(x) === NoChildren() children(x) = functor(x)[1] diff --git a/test/basics.jl b/test/basics.jl index e2d10a3..975e161 100644 --- a/test/basics.jl +++ b/test/basics.jl @@ -24,7 +24,7 @@ struct NoChild{T}; x::T; end has_children = Foo(1, 2) @test Functors.isleaf(no_children) @test !Functors.isleaf(has_children) - @test Functors.children(no_children) == () + @test Functors.children(no_children) === Functors.NoChildren() @test Functors.children(has_children) == (x=1, y=2) end @@ -352,3 +352,14 @@ end @test fmap(+, m1, n1) == Dict("x" => [5, 7], "y" => Dict(:a=>3.1, :b=>4.2)) end end + +@testset "@leaf" begin + struct A; x; end + @functor A + a = A(1) + @test Functors.children(a) === (x = 1,) + @leaf A + children, re = Functors.functor(a) + @test children == Functors.NoChildren() + @test re(children) === a +end From 7558016659e6807cce92a98e3bf9d08d912e7d3e Mon Sep 17 00:00:00 2001 From: Carlo Lucibello Date: Tue, 29 Nov 2022 09:28:25 +0100 Subject: [PATCH 2/5] move code around --- src/functor.jl | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/functor.jl b/src/functor.jl index 289c79f..1180f3e 100644 --- a/src/functor.jl +++ b/src/functor.jl @@ -1,5 +1,18 @@ +function functor end -@leaf Any +const NoChildren = Tuple{} + +function makeleaf(m::Module, T) + @eval m begin + $Functors.functor(::Type{<:$T}, x) = $Functors.NoChildren(), _ -> x + end +end + +macro leaf(T) + :(makeleaf(@__MODULE__, $(esc(T)))) +end + +@leaf Any # every type is a leaf by default functor(x) = functor(typeof(x), x) functor(::Type{<:Tuple}, x) = x, identity @@ -31,19 +44,6 @@ macro functor(args...) functorm(args...) end - -const NoChildren = Tuple{} - -function makeleaf(m::Module, T) - @eval m begin - $Functors.functor(::Type{<:$T}, x) = $Functors.NoChildren(), _ -> x - end -end - -macro leaf(T) - :(makeleaf(@__MODULE__, $(esc(T)))) -end - isleaf(@nospecialize(x)) = children(x) === NoChildren() children(x) = functor(x)[1] From f2170860e704645f5893a7722f76532b3c73c6e5 Mon Sep 17 00:00:00 2001 From: Carlo Lucibello Date: Tue, 29 Nov 2022 18:54:28 +0100 Subject: [PATCH 3/5] fix test, add docstring --- src/functor.jl | 5 +++++ test/basics.jl | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/functor.jl b/src/functor.jl index 1180f3e..58c1f1c 100644 --- a/src/functor.jl +++ b/src/functor.jl @@ -8,6 +8,11 @@ function makeleaf(m::Module, T) end end +""" + @leaf T + +Define [`functor`](@ref) for the type `T` so that `isleaf(x::T) == true`. +""" macro leaf(T) :(makeleaf(@__MODULE__, $(esc(T)))) end diff --git a/test/basics.jl b/test/basics.jl index 975e161..defea66 100644 --- a/test/basics.jl +++ b/test/basics.jl @@ -358,7 +358,7 @@ end @functor A a = A(1) @test Functors.children(a) === (x = 1,) - @leaf A + Functors.@leaf A children, re = Functors.functor(a) @test children == Functors.NoChildren() @test re(children) === a From 94fed6999c45d02e02dc90a688197479dadf16ac Mon Sep 17 00:00:00 2001 From: Carlo Lucibello Date: Tue, 29 Nov 2022 19:05:56 +0100 Subject: [PATCH 4/5] add `@leaf` to documentation --- docs/src/api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/src/api.md b/docs/src/api.md index 5d1c200..fe74379 100644 --- a/docs/src/api.md +++ b/docs/src/api.md @@ -1,6 +1,7 @@ ```@docs Functors.fmap Functors.@functor +Functors.@leaf ``` ```@docs From 71c7220d683e3cf247559643c0f59a4f009dc1ca Mon Sep 17 00:00:00 2001 From: Carlo Lucibello Date: Sun, 4 Dec 2022 10:27:47 +0100 Subject: [PATCH 5/5] simplify macro --- src/functor.jl | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/functor.jl b/src/functor.jl index 58c1f1c..1fb22b9 100644 --- a/src/functor.jl +++ b/src/functor.jl @@ -2,19 +2,13 @@ function functor end const NoChildren = Tuple{} -function makeleaf(m::Module, T) - @eval m begin - $Functors.functor(::Type{<:$T}, x) = $Functors.NoChildren(), _ -> x - end -end - """ @leaf T Define [`functor`](@ref) for the type `T` so that `isleaf(x::T) == true`. """ macro leaf(T) - :(makeleaf(@__MODULE__, $(esc(T)))) + :($Functors.functor(::Type{<:$(esc(T))}, x) = ($Functors.NoChildren(), _ -> x)) end @leaf Any # every type is a leaf by default