In Julia, functions are objects like any other. This offers a number of interesting mechanisms, such as for example the ability for a function to return another function. Let’s use a simple example: the logistic map. It is defined by $x_{n+1} = a\times x_n\times(1-x_n)$, and $x_0 \in [0;1]$.

If we wanted to do this calculation, we could write a function that takes two arguments, a and x, and return a*x*(1.0-x). But there is no reason to expect that $a$ (a parameter) will change, so what we might want to do instead is return a function with a “built-in”.

function f(x::Number)
  return a * x * (1.0 - x)
end
f (generic function with 1 method)

Of course this function will not work, because a is currently not defined. And we do not want to hard-code the value of a, since we might want to change this parameter. So ideally, we would like to have a function to write the function f on our behalf.

Because functions are objects like any other, they can actually be returned. So we can write a function that accepts a as its argument, and then returns a function that accepts x as an argument:

function logistic(a::Number)
  return function f(x::Number)
    return a * x * (1.0 - x)
  end
end
logistic (generic function with 1 method)

Now, if we call this function, we can see that it does indeed return a function:

logistic(1.2)
(::Main.##WeaveSandBox#253.var"#f#1"{Float64}) (generic function with 1 met
hod)

We can now use this function to run our model:

m = logistic(1.4)
x0 = 0.5
m(x0)
0.35

This specific design pattern shows up in a bunch of Julia functions: isequal, for example, constructs a function that tests for equality:

istwo = isequal(2)
istwo(2)
true

Sometimes, thinking about returning a function with “built-in” arguments can simplify your high-level code a lot!