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.