A function is a set of statements organized together to perform a specific task. Functions in programming work mostly like function in Math. You give functions some input, they generate output based on the input provided.
There are 2 types of functions in Elixir −
Functions defined using the fn..end construct are anonymous functions. These functions are sometimes also called as lambdas. They are used by assigning them to variable names.
Functions defined using the def keyword are named functions. These are native functions provided in Elixir.
Just as the name implies, an anonymous function has no name. These are frequently passed to other functions. To define an anonymous function in Elixir, we need the fn and end keywords. Within these, we can define any number of parameters and function bodies separated by ->. For example,
sum = fn (a, b) -> a + b end IO.puts(sum.(1, 5))
When running above program, is run, it generates the following result −
6
Note that these functions are not called like the named functions. We have a '.' between the function name and its arguments.
We can also define these functions using the capture operator. This is an easier method to create functions. We will now define the above sum function using the capture operator,
sum = &(&1 + &2) IO.puts(sum.(1, 2))
When the above program is run, it generates the following result −
3
In the shorthand version, our parameters are not named but are available to us as &1, &2, &3, and so on.
Pattern matching is not only limited to variables and data structures. We can use pattern matching to make our functions polymorphic. For example, we will declare a function that can either take 1 or 2 inputs (within a tuple) and print them to the console,
handle_result = fn {var1} -> IO.puts("#{var1} found in a tuple!") {var_2, var_3} -> IO.puts("#{var_2} and #{var_3} found!") end handle_result.({"Hey people"}) handle_result.({"Hello", "World"})
When the above program is run, it produces the following result −
Hey people found in a tuple! Hello and World found!
We can define functions with names so we can easily refer to them later. Named functions are defined within a module using the def keyword. Named functions are always defined in a module. To call named functions, we need to reference them using their module name.
The following is the syntax for named functions −
def function_name(argument_1, argument_2) do #code to be executed when function is called end
Let us now define our named function sum within the Math module.
defmodule Math do def sum(a, b) do a + b end end IO.puts(Math.sum(5, 6))
When running above program, it produces following result −
11
For 1-liner functions, there is a shorthand notation to define these functions, using do:. For example −
defmodule Math do def sum(a, b), do: a + b end IO.puts(Math.sum(5, 6))
When running above program, it produces following result −
11
Elixir provides us the ability to define private functions that can be accessed from within the module in which they are defined. To define a private function, use defp instead of def. For example,
defmodule Greeter do def hello(name), do: phrase <> name defp phrase, do: "Hello " end Greeter.hello("world")
When the above program is run, it produces the following result −
Hello world
But if we just try to explicitly call phrase function, using the Greeter.phrase() function, it will raise an error.
If we want a default value for an argument, we use the argument \\ value syntax −
defmodule Greeter do def hello(name, country \\ "en") do phrase(country) <> name end defp phrase("en"), do: "Hello, " defp phrase("es"), do: "Hola, " end Greeter.hello("Ayush", "en") Greeter.hello("Ayush") Greeter.hello("Ayush", "es")
When the above program is run, it produces the following result −
Hello, Ayush Hello, Ayush Hola, Ayush