functions 7: More tricks
Single line functions
There are more tricks you can do with functions in Julia. If the function is short, you can simply define it as shown:
y(x) = 2x + 3
Output:
y (generic function with 1 method)
Noe we call y(7)
as shown below:
y(7)
Output:
17
Doesn’t it look very mathematical? That’s why many math people use Julia and I feel its better for A.I, as A.I is nothing but math.
Functions acting on a vector
Do you know that a function can operate on a vector? We use the same function y()
defined above on a vector, see the code below:
y.([1, 2, 3, 4])
Output:
4-element Array{Int64,1}:
5
7
9
11
See how y()
just takes single argument x
and returns a value, but y.()
that is with a dot can take a vector, operate on it element wise one by one, pack it into a vector and return it out. It’s not that functions in a single line can do it, any function can do it as shown below:
function y1(x)
2x + 3
end
Output:
y1 (generic function with 1 method)
y1.([1, 2, 3, 4])
Output:
4-element Array{Int64,1}:
5
7
9
11
And this function with a .
can operate on ranges too:
y.(1:10)
Output:
10-element Array{Int64,1}:
5
7
9
11
13
15
17
19
21
23
Using functions with map
There is a function called map()
which takes function as argument and iterateable thing as second argument, say Array
, Tuple
or Range
, then it takes each element in the iterator, apply the function on it, takes the result, packs it into an array and returns it to us.
Take a look at the code below, see how we map y
on to a Array
map(y, [1, 2, 3, 4])
Output:
4-element Array{Int64,1}:
5
7
9
11
Anonymous function
It is not that a function should always have a name, it could be anonymous too, take a look at the code below, type it and execute it:
map(x -> 2x + 3, [1, 2, 3, 4])
Output:
4-element Array{Int64,1}:
5
7
9
11
We have map()
, rather than giving a name of a function as the first argument, we give x -> 2x + 3
, that is the function has no name, but an argument x
followed by arrow ->
followed by the return value 2x + 3
, and it works like charm.
Variable Arguments
Its not that there must be fixed set of arguments that are passed to a function, you can pass variable number of arguments too as shown, type the function below in a Jupter lab cell:
function vararg_sum(numbers...)
total = 0
for number in numbers
total += number
end
total
end
Output:
vararg_sum (generic function with 3 methods)
So a function was created, now let’s use it with a single argument:
vararg_sum(8)
Output:
8
So it works. Now let’s try many arguments:
vararg_sum(8, 2, 3, 4, 5)
Output:
22
It works too! We will soon see how it works.
A variable that gets variable argument is at the end of the function. It has a name numbers
in out case, and is followed by a triple dot ...
as in function vararg_sum(numbers...)
. Inside the function the variable named numbers
and not numbers...
stores all the argument. We will see how it stores soon. Julia gets a hint hat a variable need to store vrible arguments if its followed by triple dot ...
.
A variable argument variable should always be at the end of the function if we are using other variables as named and positional arguments. The below function find total of numbers
and adds it with a base base
. As you can see the variable argument is at the end of the function.
function vararg_sum_with_base(base = 0, numbers...)
total = base
for number in numbers
total += number
end
total
end
Output:
vararg_sum_with_base (generic function with 2 methods)
and once again it works as shown below:
vararg_sum_with_base(5, 1, 2, 3, 4)
Output:
15
In the below example, all we are interested is to see what numbers
hold. So let’s print it out:
function vararg(base = 0, numbers...)
total = base
println(numbers)
println(typeof(numbers))
end
Output:
vararg (generic function with 2 methods)
We call the function
vararg(1, 2, 3, 4, 5)
(2, 3, 4, 5)
NTuple{4,Int64}
As you see number
inside the function is nothing but a Tuple
packed with all the values we pass as argument.
Piping / Chaining functions
Julia has this nice idea of chaining functions, the below code is equivalent to sum(1:10)
:
1:10 |> sum
Output:
55
So in the above code we see that 1:10
is piped to sum()
. The output of this can be piped to sqrt()
as shown below:
1:10 |> sum |> sqrt
Output:
7.416198487095663
So the above code is equivalent to sqrt(sum(1:10))
, but it looks more elegant. The same operation is done by code below using the circle operator, you can type it by typing \circ
and pressing Tab
in your notebook:
(sqrt ∘ sum)(1:10)
Output:
7.416198487095663
Notice how in piping things pass from left to right here 1:10 |> sum |> sqrt
and right to left here (sqrt ∘ sum)(1:10)
.
So these are the useful things about functions I feel we as data scientist must know.
You can get the Jupyter notebook file for this blog here https://gitlab.com/data-science-with-julia/code/-/blob/master/functions.ipynb.