How to make functions multipliable?

I want to make functions be able to be multiplied:

f(x) = x^2
g = 3 * f
g(10) # == 300

Is this achievable?

No. This is not feasible. However you can do

g(args...) = 3 * f(args...)

Shouldn’t it be g(args... ; ka...) = 3 * f(args... ; ka...)?

1 Like

You certainly can do this:

julia> function Base.:*(x::Number, f::Function)
         y -> x * f(y)
       end

julia> f(x) = x^2
f (generic function with 1 method)

julia> g = 3 * f
#13 (generic function with 1 method)

julia> g(10)
300

but I wouldn’t recommend it. This is a form of Type Piracy which we don’t recommend because it can cause unexpected effects in other users’ code.

5 Likes

Maybe you want to pass multiple arguments to an inner function like this?

julia> f(x,y;z) = x^2 + y^2 + z^2 # many parameters
f (generic function with 1 method)

julia> g(func,newarg) = 3*func(newarg) # enclosing function
g (generic function with 1 method)

julia> x = 10; z = 5; 

julia> y = 3 
3

julia> g( y -> f(x,y,z=z), y )
402


You can also compose:

julia> f(x) = x^2
f (generic function with 1 method)

julia> g(x) = 3*x
g (generic function with 1 method)

julia> 10 |> f |> g
300

julia> (g ∘ f)(10)   # \circ
300


Sure, if it has keyword arguments then that works.

You can also do a callable struct

julia> struct G{T}
           f::T
       end

julia> (x::G)(args...; kwargs...) = 3 * x.f(args...; kwargs...);

julia> f(x, y) = x + y;

julia> g(1, 2)
9
1 Like

This works but I don’t know if is a good practice:

multiplication(x) = y -> y*x 
g = multiplication(3) ∘ f
g(10) #300

or

g = (x -> 3x) ∘ f
g(10) #300
1 Like

Maybe worth noting that every function has a type, and thus you can do this for your one specific function without piracy.

julia> Base.:(-)(::typeof(f)) = x -> -f(x)

julia> map(-f, [1,2,3])
3-element Vector{Int64}:
 -1
 -4
 -9
7 Likes