Monday, January 30, 2017

Elixir - Functions

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:

  1. Anonymous function 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.
  2. Named function Functions defined using the def keyword are named functions. These are native functions provided in Elixir.

Anonymous functions

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, it produces following result:
6
Note that these functions are not called like the named functions. We have a '.' between the function name and its arguments.

Using the Capture operator

We can also define these functions using the capture operator. This is actually a shorthand method to create functions. In order to define the above sum function using the capture operator,
sum = &(&1 + &2)
IO.puts(sum.(1, 2))
When running above program, it produces 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 functions

Pattern matching is not only limited to variables and data structures. We can use pattern matching to make our functions polymorphic. For example, If we want to declare a function that can either take 1 or 2 inputs(within a tuple) and prints 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 running above program, it produces following result:
Hey people found in a tuple!
Hello and World found!

Named functions

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.
Lets have a look at the syntax of named functions:
def function_name(argument_1, argument_2) do
    #code to be executed when function is called
end
Now let us define our own named function sum within module Math.
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

Private functions

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 running above program, it produces following result:
Hello world
But if we just try to explicitly call phrase function, using Greeter.phrase(), it'll raise an error.

Default arguments

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 running above program, it produces following result:
Hello, Ayush
Hello, Ayush
Hola, Ayush

No comments:

Post a Comment