# Implementing a pointwise arithmetic on functions

Hey,

I just came across a problem that I am sure can be solved elegantly in Julia but I am lacking a good starting angle. Assume that I have a collection of functors (callable types) of the form

``````struct Functor
f::function
end

(f::Functor)(x)::Real = f.f(x)
``````

This makes sure that all objects of type `Functor` can be called with a single argument `x` (which would have to be checked in a proper constructor…)

What would be the best way to implement point-wise arithmetic on these functors? I.e., I’d like to be able to create a new functor via arbitrary Julia expressions treating functor objects as reals. Something like

``````a = Functor(sin)
b = Functor(cos)
c = @compose a + exp(b) # c should also be of type Functor
c(1) # should return sin(1) + exp(cos(1))
``````

should work. Not quite sure but I suspect this is a macro problem since I essentially need to treat the argument to `@compose` as Julia expression, replace all references to functors by their pointwise evaluation and then evaluate the expression.

Are macros the way to go here or are there better options?

Macros work on syntax but here you are talking about the type of variables which are not known until the function runs. If you want to create a macro you need to think about the input and output syntax of the macro. A good start is to write down a few examples by hand, and then write the macro to do it. If you can’t write down the syntactic transformation by hand, then you can’t use a macro.

An example could be, input syntax: `a + exp(b)`, output syntax `Functor(x -> a(x) + exp(b(x)))`.

1 Like

I see, so I will essentially have to figure our which symbols in the input syntax point to objects of type Functor in the enclosing environment, and replace these with calls to <>(x) in the input expression. Should be doable, thx.

Generally speaking though, metaprogramming is the way to go here, right? Sub-typing `Real` won’t get me anywhere since I cannot pass arguments, I guess.

If you just want a syntactic transform you could do something like

``````apply(f, y) = f
apply(f::Functor, y) = f(y)

macro compose(expr)
s = gensym()
_compose!(expr,s)
return :(Functor(\$s -> \$expr))
end

function _compose!(expr, s)
isa(expr, Symbol) && return :(apply(\$expr, \$s)
isa(expr, Expr) || return expr
for i in 1:length(expr.args)
expr.args[i] = _compose!(expr.args[i], s)
end
return expr
end
``````
``````julia> a = Functor(sin)
Functor(sin)

julia> b = Functor(cos)
Functor(cos)

julia> c = @compose a + exp(b) # c should also be of type Functor
Functor(getfield(Main, Symbol("##5#6"))())

julia> c(1)
2.5579966843568
``````

but it is kinda strange just to replace symbols. You might have Functors being returned from other functions etc for which a macro wouldn’t work.

x) cool stuff, thx! Still struggling with a few things here.

First, super dummy question, how does

`isa(expr, Expr) || return expr`

work? What does the ‘or’ do with ‘return’? Is that something like a super concise error handling? I just can’t wrap my head around it and googling didn’t help either x)

Your solution might actually work for what I had in mind, will play around with it a bit longer, thx a lot.

Note that in principle you don’t need a macro for this. For example, if you define:

``````struct Functor{F<:Function} <: Function
f::F
end
(f::Functor)(x)= f.f(x)

for op in (:+, :-, :*, :/, :\)
@eval begin
Base.\$op(a::Functor, b) = Functor(x -> \$op(a(x), b))
Base.\$op(a, b::Functor) = Functor(x -> \$op(a, b(x)))
Base.\$op(a::Functor, b::Functor) = Functor(x -> \$op(a(x), b(x)))
end
end
for f in (:sin, :cos, :exp, :log, :+, :-)
@eval Base.\$f(a::Functor) = Functor(x -> \$f(a(x)))
end
``````

Then if you do

``````a = Functor(sin)
b = Functor(cos)
c = a + exp(b - 2)
c(1)
``````

it gives `1.073777476539272`, which is equal to `sin(1) + exp(cos(1) - 2)`.

The downside of this approach, of course, is that you need to predetermine the set of functions where you want `Functor` to automatically compose. The advantage is that, for this set, it works reliably — Julia knows exactly which things are of type `Functor`, so it won’t get confused if you have a symbol of another type, e.g.:

``````y = 17
d = a + y
d(1)
``````

will correctly give `17.841470984807895 == sin(1) + 17`. (In contrast, a macro executes right after parsing and doesn’t know the type of anything — it only knows how things are spelled.)

For a different function-composition approach, see the https://github.com/JuliaApproximation/ApproxFun.jl package. In ApproxFun, each time you compose its functions (a `Fun` type), it forms a new polynomial approximation. No matter how many functions you compose, you get a single polynomial — not only does this result in fast evaluation, but it also let’s you do things like find roots and integrate or solve PDEs.

4 Likes
1 Like

Also nice, less scoping issues and straight forward support for things like

``````c = a
for i in 1:3
global c = c + a
end
``````

Probably would need to implement a `register` function to allow post hoc addition of new compositional functions, e.g.

``````function register(f)
@eval \$f(a::Score) = Score(x -> \$f(a(x)))
end

register(:(Base.sin))
``````