Julia Functions
A function is a group of statements that perform a task together.
In Julia, a function is an object that maps a tuple of argument values to a return value.
In Julia, functions are defined using function, with the basic syntax:
function functionname(args)
expression
expression
...
expression
end
By default, a function returns the value of the last evaluated expression, so we see that there is no return statement above. Of course, if the return keyword is used, the function will return immediately:
Examples
julia> function f(x,y)
x + y
end
f (generic function with 1 method)
julia> f(2,3)
5
julia> function bills(money)
if money bills(50)
true
julia> bills(-50)
false
If a function needs to return multiple values, a tuple can be used:
Examples
julia> function mul(x,y)
x+y, x*y
end
mul (generic function with 1 method)
julia> mul(5, 10)
(15, 50)
When a function contains only one expression, you can omit the function keyword, set the function name and parameters on the left side of the equals sign, and set the expression on the right side, similar to an assignment form:
julia> f(x,y) = x + y
f (generic function with 1 method)
Without parentheses, the expression f refers to the function object, which can be passed around like any value:
julia> g = f;
julia> g(2,3)
5
Examples
julia> f(a) = a * a
f (generic function with 1 method)
julia> f(5)
25
julia> func(x, y) = sqrt(x^2 + y^2)
func (generic function with 1 method)
julia> func(5, 4)
6.4031242374328485
Like variable names, Unicode characters can also be used as function names:
julia> β(x,y) = x + y
β (generic function with 1 method)
julia> β(2, 3)
5
Return Types
We can use the :: operator to specify the return type of a function.
Examples
julia> function g(x, y)::Int8
return x * y
end;
julia> typeof(g(1, 2))
Int8
In the above example, the function will ignore the types of x and y, returning a value of type Int8.
Optional Arguments
In functions, we can set default values for parameters, so that when the parameter is not provided, the default value is used for calculation:
The following example defines a function pos with three parameters, where parameter cz is set with a default value of 0. When calling the function, this parameter can be omitted:
Examples
julia> function pos(ax, by, cz=0)
println("$ax, $by, $cz")
end
pos (generic function with 2 methods)
julia> pos(10, 30)
10, 30, 0
julia> pos(10, 30, 50)
10, 30, 50
Keyword Arguments
Sometimes we define functions that require many parameters, but calling these functions can be troublesome because we might forget the order of the parameters. For example:
function foo(a, b, c, d, e, f)
...
end
We might forget the order of parameters and call the function like this:
foo("25", -5.6987, "hello", 56, good, 'ABC')
or
foo("hello", 56, "25", -5.6987, 'ABC', good)
This looks very confusing.
Julia keyword arguments allow parameters to be identified by name rather than just by position, making these complex functions easier to use and extend.
To use keywords to mark parameters, use a semicolon ; after the function's unmarked parameters, followed by one or more key-value pairs key=value, as shown below:
Examples
julia> function foo(a, b ; c = 10, d = "hi")
println("a is $a")
println("b is $b")
return "c => $c, d => $d"
end
foo (generic function with 1 method)
julia> foo(100,20)
a is 100
b is 20
"c => 10, d => hi"
julia> foo("Hello", "", c=pi, d=22//7)
a is Hello
b is
"c => Ο, d => 22//7"
With keyword arguments, the position of parameters also matters less. The above function can also be called like this:
Examples
julia> foo(c=pi, d =22/7, "Hello", "")
a is Hello
b is
"c => Ο, d => 3.142857142857143"
Anonymous Functions
An anonymous function is a function without a name.
Anonymous functions are dynamically declared at runtime. Except for not having a function name, they are the same as standard functions.
In Julia, anonymous functions can be used in many places, such as map() and list comprehensions.
Using anonymous functions makes our code more concise.
The syntax for anonymous functions uses the -> symbol.
Examples
julia> x -> x^2 + 2x - 1
#1 (generic function with 1 method)
julia> function(x)
x^2 + 2x - 1
end
#3 (generic function with 1 method)
The above example creates a function that accepts one parameter x and returns the polynomial x^2+2x-1 evaluated at the current value.
The main use of anonymous functions is to pass them to functions that take other functions as arguments. A classic example is map, which applies a function to each element of an array and returns a new array containing the resulting values:
Examples
julia> map(round, [1.2, 3.5, 1.7])
3-element Vector{Float64}:
1.0
4.0
2.0
If the transformation function passed as the first argument to map already exists, then using the function name directly is fine. But usually the function we want to use hasn't been defined yet, so using an anonymous function is more convenient:
Examples
julia> map(x -> x^2 + 2x - 1, [1, 3, -1])
3-element Vector{Int64}:
2
14
-2
Anonymous functions that accept multiple parameters can be written using the syntax (x,y,z)->2x+y-z, while parameterless anonymous functions are written as ()->3. This syntax for parameterless functions may look strange, but it is necessary for delayed evaluation. This usage wraps a block of code into a parameterless function, which is later called as f.
For example, consider a call to get:
Examples
get(dict, key) do
# default value calculated here
time()
end
The above code is equivalent to calling get with an anonymous function containing the code. Wrapped between do and end, as shown below:
get(()->time(), dict, key)
Here the call to time is delayed by wrapping it in a parameterless anonymous function. This anonymous function is only called when dict lacks the requested key.
Nested and Recursive Functions
In Julia, functions can be nested.
The following example nests an add1 instance inside the add() function:
Examples
julia> function add(x)
Y = x * 2
function add1(Y)
Y += 1
end
add1(Y)
end
add (generic function with 1 method)
julia> d = 10
10
julia> add(d)
21
Similarly, functions in Julia can also be recursive.
Recursion refers to the method of using the function itself in its definition.
For example:
Once upon a time, there was a mountain, in the mountain there was a temple, in the temple there was an old monk telling a story to a young monk! What was the story? "Once upon a time, there was a mountain, in the mountain there was a temple, in the temple there was an old monk telling a story to a young monk! What was the story? 'Once upon a time, there was a mountain, in the mountain there was a temple, in the temple there was an old monk telling a story to a young monk! What was the story? ...'"
Below we use the ternary operator to test recursion. The ternary operator takes three operands expr ? a : b. If expr is true, the value is the result of a, otherwise it is the result of b.
Examples
julia> sum(x) = x > 1 ? sum(x-1) + x : x
sum (generic function with 1 method)
julia> sum(10)
55
The above example is used to calculate the sum of all numbers before a certain integer, up to and including that number. In this recursion, there is a base case, which is when x is 1, this value is returned.
The most famous example of recursion is calculating the nth Fibonacci number. The Fibonacci sequence refers to the sequence 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368........
Starting from the 3rd term, each term in this sequence is equal to the sum of the two preceding terms.
Examples
julia> fib(x) = x fib(10)
55
julia> fib(20)
6765
Map
The Map definition format is as follows:
map(func, coll)
Here, func is a function that is applied sequentially to each element of the collection coll. Map generally contains an anonymous function and returns a new collection.
Examples
julia> map(A -> A^3 + 3A - 3, [10,3,-2])
3-element Array{Int64,1}:
1027
33
-17
Filter
The Filter definition format is as follows:
filter(function, collection)
The filter function returns a copy of the collection, removing elements for which the function call results in false.
Examples
julia> array = Int[1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> filter(x -> x % 2 == 0, array)
1-element Array{Int64,1}:
2
YouTip