# A family of function and its arguments as argument of other custom function

I am trying to define a function which one of its arguments is a class of other functions, with diverse parameters (for example, distribution functions). So, I don’t know how to pass these parameters because the parameters, according to the distribution, doesn’t have the same pattern. For example

``````function foo(;distribution::Function, x = 0, parameters)
y = x + rand(distribution (parameters) )
return y
end
``````

In this case, I need to execute, for example:

``````# For normal(0,1)
foo(Normal, x = 2, 0,1)
# Or for normal(1,2)
foo(Normal, x = 2, 1,2)
``````

Or

``````# For TDist(ν)
foo(TDist, x = 4, ν = 2 )
``````

I spent some time looking for a solution, but I couldn’t find it. I would like a solution to include as arguments not only distributions and their parameters, but any kind of functions with several parameters.

``````julia> using Distributions

julia> function foo(distribution, x, parameters...)
y = x + rand(distribution(parameters...))
return y
end

julia> foo(Normal, 2, 0, 1)
0.7412695175676529

julia> foo(TDist, 4, 2)
1.5158055345656356
``````
1 Like

Why I can not do this?

``````function foo(distribution; x=0, parameters... )
y = x + rand(distribution(parameters...) )
return y
end
``````

Note that

``````foo(TDist,2 ,1)
0.010202203826929823
``````

But

``````foo(TDist,x=2 ,1)
UndefKeywordError: keyword argument distribution not assigned
``````

On the other hand

``````foo(TDist,2,ν=1)
UndefKeywordError: keyword argument distribution not assigned
``````

distributions’ constructors don’t take keyword arguments, don’t use them

2 Likes

``````foo(TDist,x=2 ,1)
``````

Something is not working. A concrete example: firts I am definig a function that simulate an autoregressive time series:

``````using Distributions

function simulateAR1(;ρ,σ = 1,x₀ = 0,μ = 0,T=1000)
#noise
η = rand( Normal(0,σ), T)
# My X
X = zeros(T)
# Looping
X = x₀
for t in 2:T
X[t] = ρ*X[t-1] + η[t]
end
return (X .+ μ)
end
``````

Test Ok

``````ξ = simulateAR1(ρ = 0.9)
``````

Now, I want to do some Compound Sum of any distribution (it can be the the AR(1) distribution or other)

``````function CP(distribution, λ,parameters...)
N  = rand(Poisson(λ))
A =  zeros(T,N)
for j =1:N
aux = distribution(parameters...)
for t=1:T
A[t,j]=aux[t]
end
end
Y=sum(A,dims=2)
return Y
end
``````

But

``````# In this case N poisson with lambda =2
CP(simulateAR1 ,2,  0.9)
UndefVarError: T not defined
``````

Moreover

``````CP(simulateAR1 ,2,  0.9, T =100)
MethodError: no method matching CP(::typeof(simulateAR1), ::Int64, ::Float64; T=100)
Closest candidates are:
CP(::Any, ::Any, ::Any...) at In:1 got unsupported keyword argument "T"
``````

Note, that I want input any other distributions with any kind of arguments. For example:

``````function non_ergodic1(; p₀ = .5 , p=.5 , T = 1000)
moeda = rand(Bernoulli(p))
if (moeda == 0)
p = 1
end
ξ = [  rand(Bernoulli(p)) for t in 1:T ]
return ξ
end
``````

Defining function has been a headache for me. Help!

It will be hard to interface with every function like that. One alternative is to keep the internal interface fixed and use closures:

``````function foo(distribution::F, x) where {F<:Function}
y = x + rand(distribution())
end

# call with
x = 2.0
foo(() -> Normal(0,1), x)
``````

Thus, your function expects, always, a function without parameters (or whatever), and interfacing with it is done by defining anonymous functions which adapt to that interface.

3 Likes

``````function CP(distribution::F, λ;T=1000) where {F<:Function}
N  = rand(Poisson(λ))
A =  zeros(T,N)
for j =1:N
aux = distribution()
for t=1:T
A[t,j]=aux[t]
end
end
Y=sum(A,dims=2)
return Y
end
``````

Notice that simulateAR1 runs ok according to the function defined above:

``````simulateAR1(ρ=0.9);
``````

Moreover

``````#Ok
CP(() -> simulateAR1(ρ=0.9), 2) ;
``````

But why this does not work?

``````CP(simulateAR1(ρ=0.9), 2)
``````

Thanks!

This notation define a new function, without parameters, that returns the result of the right side. You are passing the function, not the result of the evaluation of the function, which is what you do in the second case:

``````() -> Normal(1.0)

# or

f() = Normal(1.0)
``````

are function definitions, the first anonymous, and you are using that in that case, the second one just a regular function, without parameters.

`Normal(1.0)` is the call to the `Normal` function and returns a value (the distribution), not a function.

1 Like