Generic function to call arbitrary Julia function and its arguments

Hi there,

I am currently migrating from R. In R, i used the “do.call” function for many of own functions, which is a generic function that allows to call any arbitrary R function with its arguments in a string. This comes handy if you work with a lot of different distributions in a bigger script - that way I can change sampling procedure relatively easy and fast. Is there something similar in Julia?

Something like:

func = randn
params = "n = 1000, mu = 1, sd = 2"
do.call(func, params)

I thought I could instead just create a module where I use the match package (Switch-Case seems to be not supported in Julia?) and manually add the distributions of interest, but the above case seems more convenient to me and I can also use it for other cases. I would assume that the latter case is faster though?

Thank you for your help!

Best regards,

First, its good to quote your code with ```.

Second, you can store your parameters as a NamedTuple and splat that into you distribution. Like

func = randn
params = (n=1000, mu = 1, sd = 2)
func(;params...)
4 Likes

Thank you, fantastic and exactly what I was looking for!

I’d suggest checking out the Distributions.jl package for this kind of thing. Then you can just pass a distribution object to your function and rand should just work. So something like

using Distributions

function f(D, n)
    x = rand(D, n)
    mean(x)
end

will work no matter if you pass Normal(2, 3), InverseGamma(4, 7), or even a new distribution that you create and define a rand method for. @BeastyBlacksmith’s solution above will certainly work, but you’ll get a lot more flexibility using a package like Distributions.jl than dealing with just the rand* functions in Base.

3 Likes

Thank you! Distributions.jl looks really nice I will have a look at it!

Note the following difference between arg splatting params... and keyword splatting ;params....
IMO arg splatting with named tuples is a source of bugs and should be avoided.

julia> params = (n = 1000, mu = 1, sd = 2)
(n = 1000, mu = 1, sd = 2)

julia> f(args...;kw...) = args, kw
f (generic function with 1 method)

julia> f(params...)
((1000, 1, 2), Base.Iterators.Pairs{Union{},Union{},Tuple{},NamedTuple{(),Tuple{}}}())

julia> f(;params...)
((), Base.Iterators.Pairs(:n => 1000,:mu => 1,:sd => 2))
1 Like

thats right, I,ll add the ; in my original post.