Functors.jl
Parameterise all the things
Install / Use
/learn @FluxML/Functors.jlREADME
Functors.jl
Functors.jl provides tools to express a powerful design pattern for dealing with large / nested structures, as in machine learning and optimisation. For large machine learning models it can be cumbersome or inefficient to work with parameters as one big, flat vector, and structs help manage complexity; but it is also desirable to easily operate over all parameters at once, e.g. for changing precision or applying an optimiser update step.
Basic Usage
Functors.jl provides fmap to make those things easy, acting as a 'map over parameters':
julia> using Functors
julia> struct Foo
x
y
end
julia> model = Foo(1, [1, 2, 3])
Foo(1, [1, 2, 3])
julia> fmap(float, model)
Foo(1.0, [1.0, 2.0, 3.0])
It works also with deeply-nested models:
julia> struct Bar
x
end
julia> model = Bar(Foo(1, [1, 2, 3]))
Bar(Foo(1, [1, 2, 3]))
julia> fmap(float, model)
Bar(Foo(1.0, [1.0, 2.0, 3.0]))
[!NOTE] Up to to v0.4, Functors.jl's functionality had to be opted in on custom types via the
@functor Foomacro call. With v0.5 instead, this is no longer necessary: by default any type is recursively traversed up to the leaves andConstructionBase.constructorofis used to reconstruct it. In order to opt-out of this behaviour and make a type non traversable you can use@leaf Foo.Most users should be unaffected by the change and could remove
@functorfrom their custom types.
Further Details
The workhorse of fmap is actually a lower level function, functor:
julia> children, reconstruct = Functors.functor(Foo(1, [1, 2, 3]))
((x = 1, y = [1, 2, 3]), Functors.var"#3#6"{DataType}(Foo))
julia> reconstruct(map(float, children))
Foo(1.0, [1.0, 2.0, 3.0])
functor returns the parts of the object that can be inspected, as well as a reconstruct function that takes those values and restructures them back into an object of the original type.
To include only certain fields, pass a tuple of field names to @functor:
julia> struct Baz
x
y
end
julia> @functor Baz (x,)
julia> model = Baz(1, 2)
Baz(1, 2)
julia> fmap(float, model)
Baz(1.0, 2)
Any field not in the list will not be returned by functor and passed through as-is during reconstruction. This is done by invoking the default constructor, so structs that define custom inner constructors are expected to provide one that acts like the default.
It is also possible to implement functor by hand when greater flexibility is required. See here for an example.
For a discussion regarding the need for a cache in the implementation of fmap, see here.
Use exclude for more fine-grained control over whether fmap descends into a particular value (the default is exclude = Functors.isleaf):
julia> using CUDA
julia> x = ['a', 'b', 'c'];
julia> fmap(cu, x)
3-element Array{Char,1}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
julia> fmap(cu, x; exclude = x -> CUDA.isbitstype(eltype(x)))
3-element CuArray{Char,1}:
'a': ASCII/Unicode U+0061 (category Ll: Letter, lowercase)
'b': ASCII/Unicode U+0062 (category Ll: Letter, lowercase)
'c': ASCII/Unicode U+0063 (category Ll: Letter, lowercase)
Related Packages
Related Skills
YC-Killer
2.7kA library of enterprise-grade AI agents designed to democratize artificial intelligence and provide free, open-source alternatives to overvalued Y Combinator startups. If you are excited about democratizing AI access & AI agents, please star ⭐️ this repository and use the link in the readme to join our open source AI research team.
best-practices-researcher
The most comprehensive Claude Code skills registry | Web Search: https://skills-registry-web.vercel.app
groundhog
399Groundhog's primary purpose is to teach people how Cursor and all these other coding agents work under the hood. If you understand how these coding assistants work from first principles, then you can drive these tools harder (or perhaps make your own!).
last30days-skill
10.3kAI agent skill that researches any topic across Reddit, X, YouTube, HN, Polymarket, and the web - then synthesizes a grounded summary
