Elixir Fundamentals
Mix.install([
{:kino, "~> 0.10.0"}
])
Introduction to Functions in Elixir
Elixir is a functional programming language where functions are first-class citizens. Let’s explore the different ways to create and use functions in Elixir.
Named Functions
Named functions in Elixir are defined within modules using the def
keyword. They must be defined inside modules, which serve as a way to group related functions together.
Basic Function Definition
defmodule Math do
def add(x, y) do
x + y
end
# Single-line function definition using do:
def subtract(x, y), do: x - y
end
Math.add(5, 3)
Math.subtract(10, 4)
Default Arguments
Elixir allows you to specify default values for function arguments using the \\
syntax:
defmodule Calculator do
# y will default to 0 if not provided
def add(x, y \\ 0), do: x + y
# z will default to 1 if not provided
def power(x, z \\ 1) do
x ** z
end
end
Calculator.add(5)
Calculator.add(5, 3)
Calculator.power(2)
Calculator.power(2, 3)
Anonymous Functions
Anonymous functions (also called lambda functions) are functions without a name. They are created using the fn
keyword:
add = fn x, y -> x + y end
add.(2, 3)
Capture Operator (&)
Elixir provides a shorthand syntax using the capture operator (&
), though it’s recommended to use it sparingly for readability:
# These are equivalent:
add1 = fn x, y -> x + y end
add2 = &(&1 + &2)
add1.(5, 5)
add2.(5, 5)
Pattern Matching
Pattern matching is a powerful feature in Elixir used for data destructuring and flow control.
Basic Pattern Matching
# Simple assignment (pattern matching)
x = 1
# Tuple pattern matching
{name, age} = {"Alice", 25}
name
age
Pattern Matching with Pin Operator (^)
name = "Alice"
{^name, new_age} = {"Alice", 30}
Pattern Matching in Lists
[head | tail] = [1, 2, 3, 4]
head
tail
[first, second | rest] = [1, 2, 3, 4]
first
second
rest
Pattern Matching in Function Definitions
defmodule Greeting do
def say("hello"), do: "Hi there!"
def say("bye"), do: "Goodbye!"
def say(_), do: "I don't understand"
end
Greeting.say("hello")
Greeting.say("bye")
Greeting.say("hola")
Example: List Processing with Pattern Matching
defmodule ListUtil do
# Base case: empty list
def length([]), do: 0
# Recursive case: list with head and tail
def length([_head | tail]) do
1 + length(tail)
end
end
ListUtil.length([])
ListUtil.length([1, 2, 3])
ListUtil.length(["a", "b", "c", "d", "e"])
Guards
defmodule NumberHelper do
def positive?(x) when x > 0, do: true
def positive?(x) when x <= 0, do: false
def type(x) when is_integer(x), do: "integer"
def type(x) when is_float(x), do: "float"
def type(_), do: "other"
end
NumberHelper.positive?(5)
NumberHelper.positive?(-2)
NumberHelper.type(5)
NumberHelper.type(5.5)
NumberHelper.type("hello")
Tips for Writing Elixir Functions
- Keep functions small and focused on a single task
- Use pattern matching instead of if/else when possible
- Leverage guards for input validation
- Use default arguments when it makes sense
- Consider using named functions over anonymous functions for better code organization
- Document your functions using @doc and @moduledoc
Practice Problems
Try implementing these functions to test your understanding:
- Create a factorial function using pattern matching:
defmodule Practice do
def factorial(0), do: 1
def factorial(n) when n > 0, do: n * factorial(n - 1)
end
Practice.factorial(5)
Practice.factorial(0)
- Create a function that counts occurrences in a list:
defmodule ListCounter do
def count([], _element), do: 0
def count([head | tail], element) when head == element do
1 + count(tail, element)
end
def count([_head | tail], element), do: count(tail, element)
end
ListCounter.count([1, 2, 3, 2, 4, 2], 2)
ListCounter.count(["a", "b", "a"], "a")
Common Gotchas and Best Practices
- Remember to use dot notation when calling anonymous functions
- Be careful with the pin operator to avoid accidental rebinding
- Consider performance implications when working with large lists
- Use pattern matching in function heads instead of conditional logic in the function body when possible
- Avoid deep nesting of anonymous functions