A generic function (using higher order functions) with special implementation for specific functions (as input)?

Hi,

I have the following situation: A complicated algorithm that works with a function as input parameter:

function cool_stuff(f :: Function, a::Real, b::Real) 
   ... 
end

cool_stuff could be something like integration or some optimization which is numerically complicated. For some functions (like f(x) = sin(x) or f(x) = x + 1) I have done all the math and can provide very efficient code. I nevertheless want to have one function cool_stuff with several methods. So a function cool_stuff_for_sin is not the desired solution. Question: How can I do multiple dispatch for a special function? So I guess that’s equivalent to the question if I can define subtypes of the function type?

Thanks

You can say something like

cool_stuff(f::typeof(sin), a::Real, b::Real) = cos(a+b)

Apart from that, I would say it’s not a good idea to restrict f to Function. You (or somebody else) may want to use some object a::A with a callable method a(x) instead. That wouldn’t work if A is not a subtype of Function.

1 Like

Thanks - what would be the way to restrict the argument to types that are callable?

Anything can be callable, so there’s no way to do that within the type system, basically. If reflection is a viable solution, hasmethod or applicable might be useful, but that’s easy to abuse.

There is no real way – any type can have callable methods. There is a type Callable, but it’s internal. Moreover, like Function, you can subtype it for any type. So it’s not helpful.

I wouldn’t restrict the type of f at all. If f doesn’t have a callable method (or rather not one with the signature you are using), then you get an error. If you pass f on as an argument to some other function, then it’s best to use a type parameter as in

cool_stuff(f::F, a::Real, b::Real) where F = sum(f, (a, b))

see here.

2 Likes

It’s not really relevant to the rest of the topic, but, just to be clear, defining subtypes of Function is done in the usual manner: struct Func <: Function end.

Thanks - I think using a subtype of Function is reletad as the following works fine:

struct AddSomething <: Function 
  to_add :: Real
end;

(my_f::AddSomething)(x::Real) = x + my_f.to_add

function cool_thing(f::Function, a::Real, b::Real) println("fallback") end

function cool_thing(f::AddSomething, a::Real, b::Real) println("special, parameter = ",f.to_add) end

my_func = AddSomething(3)

julia> cool_thing(x -> x+1, 0, 1)
fallback

julia> cool_thing(my_func, 0, 1)
special, parameter = 3