Skip to content

Deprecate fmap(walk, f, x, ys...) for execute(walk, x, ys...) #65

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

Merged
merged 3 commits into from
Jun 24, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ Functors.isleaf

```@docs
Functors.AbstractWalk
Functors.execute
Functors.DefaultWalk
Functors.StructuralWalk
Functors.ExcludeWalk
Expand Down
12 changes: 4 additions & 8 deletions src/Functors.jl
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module Functors

export @functor, @flexiblefunctor, fmap, fmapstructure, fcollect
export @functor, @flexiblefunctor, fmap, fmapstructure, fcollect, execute

include("functor.jl")
include("walks.jl")
Expand Down Expand Up @@ -105,7 +105,6 @@ children

"""
fmap(f, x, ys...; exclude = Functors.isleaf, walk = Functors.DefaultWalk()[, prune])
fmap(walk, f, x, ys...)

A structure and type preserving `map`.

Expand Down Expand Up @@ -190,10 +189,10 @@ use [`fmapstructure`](@ref).

For advanced customization of the traversal behaviour,
pass a custom `walk` function that subtypes [`Functors.AbstractWalk`](ref).
The form `fmap(walk, f, x, ys...)` can be called for custom walks.
The simpler form `fmap(f, x, ys...; walk = mywalk)` will wrap `mywalk` in
The call `fmap(f, x, ys...; walk = mywalk)` will wrap `mywalk` in
[`ExcludeWalk`](@ref) then [`CachedWalk`](@ref).

Here, [`ExcludeWalk`](@ref) is responsible for applying `f` at excluded nodes.
For a low-level interface for executing a user-constructed walk, see [`execute`](@ref).
```jldoctest withfoo
julia> struct MyWalk <: Functors.AbstractWalk end

Expand All @@ -202,9 +201,6 @@ julia> (::MyWalk)(recurse, x) = x isa Bar ? "hello" :

julia> fmap(x -> 10x, m; walk = MyWalk())
Foo("hello", (40, 50, "hello"))

julia> fmap(MyWalk(), x -> 10x, m)
Foo("hello", (4, 5, "hello"))
```

The behaviour when the same node appears twice can be altered by giving a value
Expand Down
13 changes: 3 additions & 10 deletions src/maps.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,4 @@
# Note that the argument f is not actually used in this method.
# See issue #62 for a discussion on how best to remove it.
function fmap(walk::AbstractWalk, f, x, ys...)
# This avoids a performance penalty for recursive constructs in an anonymous function.
# See Julia issue #47760 and Functors.jl issue #59.
recurse(xs...) = walk(var"#self#", xs...)
walk(recurse, x, ys...)
end
Base.@deprecate fmap(walk::AbstractWalk, f, x, ys...) execute(walk, x, ys...)

function fmap(f, x, ys...; exclude = isleaf,
walk = DefaultWalk(),
Expand All @@ -15,10 +8,10 @@ function fmap(f, x, ys...; exclude = isleaf,
if !isnothing(cache)
_walk = CachedWalk(_walk, prune, cache)
end
fmap(_walk, f, x, ys...)
execute(_walk, x, ys...)
end

fmapstructure(f, x; kwargs...) = fmap(f, x; walk = StructuralWalk(), kwargs...)

fcollect(x; exclude = v -> false) =
fmap(ExcludeWalk(CollectWalk(), _ -> nothing, exclude), _ -> nothing, x)
execute(ExcludeWalk(CollectWalk(), _ -> nothing, exclude), x)
14 changes: 14 additions & 0 deletions src/walks.jl
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,20 @@ The choice of which nodes to recurse and in what order is custom to the walk.
"""
abstract type AbstractWalk end

"""
execute(walk, x, ys...)

Execute a `walk` that recursively calls itself, starting at a node `x` in a Functors tree,
as well as optional associated nodes `ys...` in other Functors trees.
Any custom `walk` function that subtypes [`Functors.AbstractWalk`](@ref) is permitted.
"""
function execute(walk::AbstractWalk, x, ys...)
# This avoids a performance penalty for recursive constructs in an anonymous function.
# See Julia issue #47760 and Functors.jl issue #59.
recurse(xs...) = walk(var"#self#", xs...)
walk(recurse, x, ys...)
end

"""
AnonymousWalk(walk_fn)

Expand Down
4 changes: 4 additions & 0 deletions test/basics.jl
Original file line number Diff line number Diff line change
Expand Up @@ -378,3 +378,7 @@ end
@test zipped_iter isa Iterators.Flatten
@test collect(zipped_iter) == collect(Iterators.zip([1, 2, 3, 4, 5, 6, 7, 8].^2, [8, 7, 6, 5, 4, 3, 2, 1].^2))
end

@testset "Deprecated first-arg walk API to fmap" begin
@test (@test_deprecated fmap(Functors.DefaultWalk(), nothing, (1, 2, 3))) == (1, 2, 3)
end