# Can I dispatch on (mathematical) functions?

**URL:** <https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577>\
**Category:** General Usage\
**Created:** [October 30, 2023, 3:55pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577 "2023-10-30T15:55:48Z")\
**Posts on this page:** 16\
**Page:** 1

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 3:55pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/1 "2023-10-30T15:55:48Z")

</div>

Hi,

**TLDR: Is it possible to dispatch on (mathematical) functions ?**

> **Broad context and reasons I am asking this**
>
> > In this (just registered) package [GitHub - lrnv/WilliamsonTransforms.jl](https://github.com/lrnv/WilliamsonTransforms.jl) I implemented a bijective mapping between the set of non-negative random variables \mathcal X and a set of d-monotone functions \mathcal F. You may take a look at the documentation there : [Home · WilliamsonTransforms.jl](https://lrnv.github.io/WilliamsonTransforms.jl/dev/) to see what I am talking about.  
> > Now that i have the general formula, this is great, but I wanted to implement some specific cases where the transforms are known, using dispatch. In one way, I can dispatch on random variables, but on the other way I cannot dispatch on functions…  
> > The generic version is much more expensive than the particular cases, where the result is simply known.

Consider this functional operator:

```julia
function op(F)
     return "Generic"
end
square(x) = x^2
function op(F <: typeof(square))
    return "Specific for the square function"
end
op(x -> x^2) # does not work as intended..

```

You may assume that all functions that I will use are univariate continuous functions from \mathbb R^+ to \mathbb R^+. I think it might then be possible to check them using e.g. `Symbolics.jl`, against a “library” of a few implemented special cases. But is that possible to do in the type system ?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 30, 2023, 4:01pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/2 "2023-10-30T16:01:46Z")

</div>

no, not like this, in fact, every `x -> x^2` is a new function right now… but even if we solve that(we kinda can’t because world age?), there’s no way to know `square(x)` and `x->x^2` are the same function

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:13pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/3 "2023-10-30T16:13:28Z")

</div>

> [@jling](#):
>
> there’s no way to know `square(x)` and `x->x^2` are the same function

Well, I disagree:

```julia
using Symbolics

square(x) = x^2
contestant_1 = x -> x^2
contestant_2 = x -> x^3

@variables t

isequal(square(t),contestant_1(t)) # true
isequal(square(t),contestant_2(t)) # false

```

But maybe indeed not at type system level indeed. If not, how can i construct a tool that will “identify” a given function argument and put this identification into the type system ?

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 30, 2023, 4:18pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/4 "2023-10-30T16:18:16Z")

</div>

that’s the same as saying

```julia
(x->x^2)(3.0) === (3.0)^2

```

you want this to happen in type system no? without actually running the code. The language compiler does not work symbolically

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:20pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/5 "2023-10-30T16:20:00Z")

</div>

No it is not the same thing as your version only checks for the value 3.0 while mine checks for the expression itself…

I understood that this will not happend in the type system, fair enough. But I still need it to happend ^^

---

<div class="post-metadata">

**Author:** ![sbuercklin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sbuercklin/32/15728_2.png) [@sbuercklin](https://discourse.julialang.org/u/sbuercklin)\
**Post date:** [October 30, 2023, 4:23pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/6 "2023-10-30T16:23:03Z")

</div>

This is exactly what `ChainRules.jl` does with `rrule`s and `frule`s, no?

You don’t get the subtyping that I think you’re looking for, but so long as you’re using actual named functions and not anonymous functions, it works

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

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

julia> h(::typeof(f)) = "Squaring"
h (generic function with 1 method)

julia> h(::typeof(g)) = "Cubing"
h (generic function with 2 methods)

julia> h(f)
"Squaring"

julia> h(g)
"Cubing"

```

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 30, 2023, 4:23pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/7 "2023-10-30T16:23:09Z")

</div>

> [@lrnv](#):
>
> I understood that this will not happend in the type system, fair enough. But I still need it to happend ^^

that’s impossible, because dispatch is a type system thing. You can make your own dispatch system and always ask user to call that function. And in the function, you run your variable through functions and see if the values (expression in Symbolics.jl) returned are the same.

---

<div class="post-metadata">

**Author:** ![jling](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jling/32/212909_2.png) [@jling](https://discourse.julialang.org/u/jling)\
**Post date:** [October 30, 2023, 4:24pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/8 "2023-10-30T16:24:54Z")

</div>

OP wants this to work

```julia
julia> h(x->x^2)
ERROR: MethodError: no method matching h(::var"#1#2")

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:25pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/9 "2023-10-30T16:25:46Z")

</div>

> [@jling](#):
>
> You can make your own dispatch system and always ask user to call that function. An in the function, you run your variable through functions and see if the values (expression in Symbolics.jl) returned are the same.

Yes this is what I am currently trying to do

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:29pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/10 "2023-10-30T16:29:16Z")

</div>

Ok this works:

```julia
library(x) = (
    x^2 => :SquareExemple,
    exp(-x) => :Independant,
    (1+x)^(-1) => :Clayton
)

function identify(f, library)
    @variables t
    
    # This did not work: 
    # return library(t)[f(t)]

    f_t = f(t)
    for (g_t,name) in library(t)
        if isequal(f_t,g_t)
            return name
        end
    end
    return :NotFound
end

identify(contestant_1,library)
identify(contestant_2,library)
identify(x -> 1/(1+x),library)

```

But now I probably want something like this to lift up the information in the type system for future uses:

```julia
abstract type Transform end
struct ClaytonTransform<:Transform end
struct IndependentTransform<:Transform end
struct SquareExemple<:Transform end
struct GenericTransform{Tf}<:Transform
    f::Tf
    function Transform(f)
        id = identify(f,library)
        if id == :NotFound
            return new{Tf}(f)
        elseif id == :Clayton
            return ClaytonTransform()
        elseif id == :Independant()
            return IndependentTransform()
        elseif id == :SquareExemple
            return SquareExemple()
        end
    end
end

```

If the list grows a bit longer, that would be tedious to manage in the package repository… But I guess I only have about 20 particular cases so I can mange this.

---

<div class="post-metadata">

**Author:** ![savq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/savq/32/22063_2.png) [@savq](https://discourse.julialang.org/u/savq)\
**Post date:** [October 30, 2023, 4:41pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/11 "2023-10-30T16:41:03Z")

</div>

> [@lrnv](#):
>
> ```julia
> # This did not work: 
> # return library(t)[f(t)]
> 
> ```

`library` is returning a tuple of pairs, you should use a `Dict` instead.

---

<div class="post-metadata">

**Author:** ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)\
**Post date:** [October 30, 2023, 4:46pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/12 "2023-10-30T16:46:08Z")

</div>

I may be missing the point, but why not just use ordinary named functions for the known transforms as follows:

```julia
square_example(x) = x^2
exponential_neg_example(x) = exp(-x)

do_transform(f::F) where {F <: Function} = "I've done a generic transform"
do_transform(f::typeof(square_example)) = "I've transformed x^2!"
do_transform(f::typeof(exponential_neg_example)) = "I've transformed exp(-x)!"

do_transform(square_example) |> println
do_transform(exponential_neg_example) |> println
do_transform(exp) |> println

```

which produces the output

```julia
I've transformed x^2!
I've transformed exp(-x)!
I've done a generic transform

```

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:47pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/13 "2023-10-30T16:47:10Z")

</div>

Because I want the user to be able to pass the function without knowing its name

---

<div class="post-metadata">

**Author:** ![PeterSimon](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/petersimon/32/25193_2.png) [@PeterSimon](https://discourse.julialang.org/u/PeterSimon)\
**Post date:** [October 30, 2023, 4:55pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/14 "2023-10-30T16:55:15Z")

</div>

I would think that it would be useful for the user to be aware of which functions have known transforms and are therefore much cheaper. In that case giving them specific names for the user to invoke doesn’t seem too onerous. Just my opinion.

---

<div class="post-metadata">

**Author:** ![lrnv](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lrnv/32/19373_2.png) [@lrnv](https://discourse.julialang.org/u/lrnv)\
**Post date:** [October 30, 2023, 4:56pm UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/15 "2023-10-30T16:56:56Z")

</div>

I Agree with you. The current sketch

```julia
using Symbolics

library(x) = Dict(
    x^2 => :SquareExemple,
    exp(-x) => :Independant,
    (1+x)^(-1) => :Clayton
)
function identify(f, library)
    @variables t
    return get(library(t),f(t),:NotFound)
end

abstract type Transform end
struct ClaytonTransform<:Transform end
struct IndependentTransform<:Transform end
struct SquareExemple<:Transform end
struct GenericTransform{Tf}<:Transform
    f::Tf
end
function Transform(f)
    id = identify(f,library)
    if id == :NotFound
        return GenericTransform{typeof(f)}(f)
    elseif id == :Clayton
        return ClaytonTransform()
    elseif id == :Independant
        return IndependentTransform()
    elseif id == :SquareExemple
        return SquareExemple()
    end
end

Transform(square)
Transform(x -> x^2)
Transform(x -> x^3)
Transform(x -> exp(-x))

```

allows for discoverability (if all structs are exported), but also to pass an unknown function. The user (let’s face it: its me) might not even know its own function, might result from an algorithm or something.

---

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [October 31, 2023, 2:20am UTC](https://discourse.julialang.org/t/can-i-dispatch-on-mathematical-functions/105577/16 "2023-10-31T02:20:33Z")

</div>

How crucial it is for `op(x -> x^2)` specifically to dispatch?  
There are dispatchable alternatives that don’t involve special `square(x)` definition:

```julia
op(Base.Fix2(^, 2)) # works, but not convenient and hard to read

using Accessors
op(@optic _^2) # fundamentally the same as above, but with nicer syntax

```

these are for case where dispatch by “any power function” is enough, `2` isn’t a compile-time parameter. For that you would need static integers:

```julia
using StaticNumbers
op(@optic _^static(2))

```

But think first whether your really need this?..
