Notesclub

# Functions

``````Mix.install([
{:jason, "~> 1.4"},
{:kino, "~> 0.9", override: true},
{:hidden_cell, github: "brooklinjazz/hidden_cell"},
{:smart_animation, github: "brooklinjazz/smart_animation"}
])``````

Home Report An Issue MazesControl Flow

## Review Questions

Upon completing this lesson, a student should be able to answer the following questions.

• How do we define a function?
• How do we call a function?
• How do we use the pipe operator `|>` to pipe function calls into each other?

## Functions

Elixir is a functional programming language. So you can imagine that functions must be important. But what is a function?

### Input And Output (IO)

A function is a set of repeatable instructions. A function accepts some input, and returns some output.

``````  flowchart LR
Input --> Output``````

### Black Box

How the function converts some input to some output is often referred to as a black box. It’s a black box because you don’t need to know (or can’t know) the details of how it works.

``````  flowchart LR
Input --> B[Black Box] --> Output``````

### Creating A Function

Let’s create a function called `double` which will take in a number and double its value.

``````flowchart LR
A --> B[double] --> C``````

Now, let’s create our first function. At first, it’s going to do nothing. A function must have an output. We can return `nil` for now.

``double = fn -> nil end``

You may see some weird-looking output like `#Function<45.65746770/0 in :erl_eval.expr/5>`. Don’t worry too much about that. It’s how Elixir represents a function internally.

### Parts Of A Function

Let’s break down what we did above.

1. `double` is a variable name. Often you’ll refer to it as the function name. It can be any valid variable name.

2. We bind `double` to an anonymous function. The anonymous function is everything from the `fn` to the `end`.

``````flowchart LR
A[function name] --> B[=]
B --> C[anonymous function]``````
3. Elixir uses the `fn` keyword to define a function.

4. The next value `->` separates the function head and the function body.

5. The function head describes the input of the function. In this example, it’s empty.

6. The function body contains the function’s implementation or black box . In this example, it returns `nil`.

7. Elixir uses the `end` keyword to stop creating a function.

``````flowchart LR
direction LR
a[function name] --> B
c[function body] --> C
subgraph a[Breaking Down A Function]
direction LR
A[fn] ---- B
B[->] --- C
C[nil] --- D
D[end]
end``````

### Calling A Function

Our `double` function doesn’t do much at this point, but let’s see the output that it returns.

We use the `.()` syntax in Elixir to get the function’s output. We often say we are executing or calling a function.

``double.()``

`double` should return `nil` because that’s all we’ve told it to do so far. However, we want it to multiply a number by `2`.

To do that, we need to make the function accept some input. To do this, we define a parameter in the function like so.

``double = fn parameter -> nil end``

You’ll notice a warning above. That’s because Elixir is smart and lets us know that we’ve created a parameter, but we’re not using it.

In Elixir, you can ignore this warning for unused variables by starting them with an underscore `_`

``double = fn _parameter -> nil end``

No more warning 😀 But we actually want to use that parameter, so let’s modify the function to return the parameter instead.

``double = fn parameter -> parameter end``

The parameter is named `parameter` here for the sake of example. But it works a lot like a variable, and it can be named any valid variable name.

Let’s rename it to `number` to clarify that we expect the input to be a number.

``double = fn number -> number end``

Now the function head takes in a value. We have to pass it an argument when we call it. The argument will be bound to the parameter when the function executes. We’ll give it the integer `2`.

``double.(2)``

Notice that if you try to call the function without an argument, it fails because it expects an argument. Not all languages do that, but Elixir is pretty smart 😎

``double.()``

Great, now all that’s left is to multiply the parameter by `2`. You should be familiar with this from the previous sections.

``double = fn number -> number * 2 end``

And you can use it to double any number.

``double.(10)``
``double.(11)``
``double.(10 ** 2 - 1)``

Under the hood, when the function runs, the parameter is bound to the argument’s value.

Let’s break down how a function executes step by step in the following slideshow.

``````frames = [
"
First, we define the `double` function and call it.
```elixir
double = fn number -> number * 2 end
double.(3)
```
",
"
The `double` function executes in place of the `double.(call)` with `number` bound to `3`.
```elixir
double = fn number -> number * 2 end
fn 3 -> 3 * 2 end
```
",
"
The function evaluates the function body between the `->` and the `end`
```elixir
double = fn number -> number * 2 end
3 * 2
```
",
"
`3` * `2` is `6`, so the function call returns `6`.
```elixir
double = fn number -> number * 2 end
6
```
"
]

SmartAnimation.new(0..(Enum.count(frames) - 1), fn i ->
Enum.at(frames, i) |> Kino.Markdown.new()
end)``````

As expected, `double.(3)` returns `6`.

``double.(3)``

### Implied Return Values

Some languages require explicit return values.

However, in Elixir the output of a function is always the last line.

For example, notice that the return value below is `first` + `second`, which equals `3`.

``````multiline_function = fn ->
first = 1
second = 2
first + second
end

multiline_function.()``````

Create a function `is_even?/1` that accepts an integer, and returns `true` if the integer is even, or `false` if the integer is odd.

``````is_even?.(2) # true
is_even?.(1) # false``````

Example solution

``is_even? = fn int -> rem(int, 2) == 0 end ``

## Multi-Parameter Functions

Functions can accept multiple inputs. Separate parameters with commas `,` to create a multi-parameter function.

``````sum3 = fn param1, param2, param3 -> param1 + param2 + param3 end

sum3.(2, 3, 4)``````

Keep in mind that the first argument will be the value of the first parameter, and the second argument will be the value of the second parameter. You can repeat this with as many parameters as you want!

``````to_list = fn a, b, c, d, e -> [a, b, c, d, e] end

to_list.(1, 2, 3, 4, 5)``````

But usually, you want to avoid having too many parameters because it makes your function hard to understand.

A parameter can be bound to any valid data type, so you could instead use an associative data structure like a map or keyword list.

### Function Arity

The number of parameters your function accepts is called the arity of the function.

A function with no parameters has an arity of zero. A function with one parameter has an arity of one, and so on.

You refer to the function as `function_name/arity` thus a function named `add_two` with two parameters is called `add_two/2`.

Create a function `calculate_force/2` that accepts a `mass` and `acceleration` parameters. The `calculate_force/2` function should return `mass * acceleration`.

``````calculate_force.(10, 10) # 100
calculate_force.(2, 4) # 8``````

Example solution

``calculate_force = fn mass, acceleration -> mass * acceleration end``

## Shorthand Syntax

Anonymous functions can be defined using a shorthand syntax. It is only an alternative and shorter version to define a function. You will sometimes see shorthand syntax, so it’s helpful to understand it. However, it should not be over-used. Otherwise, your program may be less clear.

You can still bind the anonymous function to a variable with the shorthand syntax. However, you define the function with `&()` and put the function body between the brackets.

Here’s the same `double` function using short-hand syntax.

``````double = &amp;(&amp;1 * 2)
double.(5)``````

`&1` means the first parameter. If the function had more parameters, you could access them with `&2`, `&3`, and so on.

``````add_two = &amp;(&amp;1 + &amp;2)

Using shorthand syntax, create a `subtract/2` function which subtracts two numbers.

``````subtract.(1, 1) # 0
subtract.(20, 25) # -5``````

Example solution

``subtract = &amp;(&amp;1 - &amp;2)``

Using shorthand syntax, create a `multiply_three/3` function which multiplies three numbers together.

``````multiply_three.(2, 2, 2) # 8
multiply_three.(2, 5, 3) # 30``````

Example solution

``multiply_three = &amp;(&amp;1 * &amp;2 * &amp;3)``

## First-class Functions

Functions in Elixir are first-class citizens.

For our purposes, this means we can bind functions to variables, store them in other data types, pass them as arguments to other functions.

We’ll see something like `#Function<42.3316493/1 in :erl_eval.expr/6>` if we try to view a function as data. This is the internal representation of the function in Elixir. We can only view a function this way, we cannot use this syntax in our code.

``[fn int -> int * 2 end, 2, 3, 4]``

Functions are just data as far as our programs are concerned. We can work with them like we would work with any data structure.

``````[my_function | _tail] = [fn int -> int * 2 end, 2, 3, 4]

my_function.(10)``````

If a function takes in another function as a parameter, it’s called a higher-order function. The function passed in is called a callback function.

``````callback_function = fn -> end

higher_order_function.(callback_function)``````

For example, we can create a `call_with_2/1` higher order function, that accepts a callback function, and calls it with the integer `2`.

``call_with_2 = fn callback -> callback.(2) end``

We can then use the `call_with_2/1` higher order function with an `add_three/1` callback function. This calls `add_three/1` with `2` to return `5`.

``````add_three = fn int -> int + 3 end

Instead of binding the callback function to a variable, we can pass in the anonymous function directly.

``call_with_2.(fn int -> int + 3 end)``

Callback functions are useful for creating re-usable behavior with slight alterations. For example, in Elixir we have a built-in function Enum.map/2 which we will cover in later lessons.

Enum is a module. We’ll cover modules in the next Modules reading material.

Enum.map/2 can accept a list as the first argument, and a callback function as the second argument. The callback function is applied to every element in the list to create a new list.

``Enum.map([1, 2, 3], fn element -> element * 2 end)``

Create a `call_with_10_and_20/1` function. The `call_with_10_and_20/1` function should accept a call back function, and call the function with `10` as the first argument, and `20` as the second argument.

``````add = fn int1, int2 -> end

Example solution

``call_with_10_and_20 = fn callback -> callback.(10, 20) end``

``call_with_10_and_20 = nil``

## Pipe Operator

To create more complex behavior, you’ll often compose smaller functions together. Composing functions together reflects nature of problem-solving where we take large problems and break them down into smaller ones.

To help compose functions together, Elixir provides the pipe |> operator. That’s the `|` symbol likely above your enter key, and the greater than `>` symbol side by side to make |>.

The pipe operator allows you to take the output of one function and pass it in as an argument for the input of another function.

``````flowchart LR
A[Input] --> B[Function1]
B --> C[Pipe]
C --> D[Function2]
D --> E[Output]``````

Why is this useful? Without the pipe operator you can wind up writing deeply nested function calls.

``four.(three.(two.(one.())))``

Or rebinding values between function calls.

``````a = one.()
b = two.(a)
c = three.(b)
d = four.(c)``````

But with the pipe operator, you can chain functions together.

``one.() |> two.() |> three.() |> four.()``

If a function is called with multiple arguments, the function piped in will be the first argument.

``````two(1, 2) # how to call two/2 by itself.

# How To Use The Pipe Operator
# To Call The Two/2 With One/1 As The First Argument.
one.() |> two.(2)``````

You can also pass in a value to a pipe. It’s generally non-idiomatic (not following the standards of the community) to use the pipe operator for a single value and function.

``````# Non-idiomatic
1 |> two.()

# Idiomatic
two.(1)

# Idiomatic
1 |> two.() |> three()``````

The pipe operator doesn’t change the behavior of a program. Instead, the pipe operator exists as syntax sugar to improve the clarity of your code.

Create three functions `add/2`, `subtract/2`, and `multiply/2` which add, subtract, or multiply two numbers.

Use these functions with the pipe operator |> to:

1. start with `10`.
2. add `2`.
3. multiply by `5`.
4. subtract by `4`.

Example solution

``````add = fn int1, int2 -> int1 + int2 end
subtract = fn int1, int2 -> int1 - int2 end
multiply = fn int1, int2 -> int1 * int2 end

10
|> multiply.(2)
|> subtract.(4)``````

DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.

Run `git status` to ensure there are no undesirable changes. Then run the following in your command line from the `curriculum` folder to commit your progress.

``````\$ git add .
\$ git commit -m "finish Functions reading"
\$ git push``````

We’re proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.

We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.