Hello World
IO.puts("Hello, world!")

Run the script:

elixir main.exs

This prints a line in Elixir using the IO module. It is the normal first example for a script.

Variables

Values are immutable. Rebinding creates a new binding for the name.

name = "Dan"
count = 1
active = true

These bindings hold values for the current expression flow. In Elixir, you work with new bindings instead of mutating old values.

Pattern Matching
{:ok, name} = {:ok, "Dan"}
[first | rest] = [1, 2, 3]

This pulls values out of a tuple and a list by matching the shape on the left to the data on the right.

Functions
defmodule Greeter do
  def greet(name) do
    "Hello, #{name}!"
  end
end

Greeter.greet("world")

This defines a small module with one function and then calls it. That is the standard way to group behavior in Elixir.

Function Clauses and Guards

Use multiple function heads to make branching explicit. Guards keep each clause narrow and readable.

defmodule AccessLevel do
  def label(%{role: :admin}), do: "full access"
  def label(%{role: :editor, active: true}), do: "edit access"
  def label(%{role: role}) when role in [:viewer, :guest], do: "read only"
  def label(_), do: "no access"
end

This keeps branching close to the function definition, which makes Elixir code easier to scan than one large conditional.

Pipelines

The pipe operator passes the previous result as the first argument to the next function.

users
|> Enum.filter(& &1.active)
|> Enum.map(& &1.email)
|> Enum.sort()

Prefer pipes when each step transforms the same value. Avoid hiding complex branching inside a long pipeline.

This reads top to bottom like a data flow. Each step takes the previous result and transforms it a little more.

Structs

Structs are maps with a fixed shape and a module name. They are useful for domain data.

defmodule User do
  defstruct [:id, :email, active: true]
end

user = %User{id: 1, email: "[email protected]"}

case user do
  %User{active: true, email: email} -> {:ok, email}
  %User{} -> {:error, :inactive}
end

This shows a struct as a predictable map shape for domain data, plus pattern matching on that struct in a case.

With

with flattens a sequence of pattern matches that may fail.

with {:ok, user} <- fetch_user(id),
     {:ok, plan} <- fetch_plan(user),
     true <- plan.active do
  {:ok, %{user: user, plan: plan}}
else
  false -> {:error, :inactive_plan}
  {:error, reason} -> {:error, reason}
end

Use it when each successful step feeds the next one.

This is useful when several steps can fail and each successful result feeds the next one.

Processes and Messages

Elixir processes are lightweight and communicate by sending messages.

parent = self()

spawn(fn ->
  send(parent, {:result, 42})
end)

receive do
  {:result, value} -> value
after
  1_000 -> {:error, :timeout}
end

This demonstrates Elixir’s concurrency model: lightweight processes send messages instead of sharing mutable state.

GenServer Shape

A GenServer keeps state behind a process and exposes a client API.

defmodule Counter do
  use GenServer

  def start_link(initial), do: GenServer.start_link(__MODULE__, initial)
  def increment(pid), do: GenServer.call(pid, :increment)

  @impl true
  def init(initial), do: {:ok, initial}

  @impl true
  def handle_call(:increment, _from, count) do
    next = count + 1
    {:reply, next, next}
  end
end

This is the usual GenServer layout: public API at the top, callbacks below, and state kept inside the process.

Elixir Add
defmodule Add do
  def add(param1, param2), do: param1 + param2
end

This just adds the two input numbers with the language’s normal arithmetic and returns the sum.

Elixir Add Border
defmodule AddBorder do
  def add_border(picture) do
    border = String.duplicate("*", String.length(hd(picture)))
    wrapped = Enum.map(picture, fn row -> "*" <> row <> "*" end)

    [border] ++ wrapped ++ [border]
  end
end

This builds a new grid with a * border around every side. It adds a full top and bottom row, then wraps each existing row from left and right.

Elixir Adjacent Elements Product
defmodule AdjacentElementsProduct do
  def adjacent_elements_product(input_array) do
    input_array
    |> Enum.chunk_every(2, 1, :discard)
    |> Enum.map(fn [a, b] -> a * b end)
    |> Enum.max()
  end
end

This walks through neighboring values, multiplies each pair, and keeps the biggest product it finds.

Elixir Almost Magic Square
defmodule AlmostMagicSquare do
  def almost_magic_square(a) do
    rows = Enum.chunk_every(a, 3)
    row_sums = Enum.map(rows, &Enum.sum/1)
    col_sums = for j <- 0..2, do: rows |> Enum.map(&Enum.at(&1, j)) |> Enum.sum()
    max_sum = Enum.max(row_sums ++ col_sums)

    {final_rows, _, _, _, _} = balance(rows, row_sums, col_sums, max_sum, 0, 0)
    List.flatten(final_rows)
  end

  defp balance(rows, row_sums, col_sums, max_sum, i, j) when i < 3 and j < 3 do
    diff = min(max_sum - Enum.at(row_sums, i), max_sum - Enum.at(col_sums, j))

    rows = List.update_at(rows, i, fn row -> List.update_at(row, j, &(&1 + diff)) end)
    row_sums = List.update_at(row_sums, i, &(&1 + diff))
    col_sums = List.update_at(col_sums, j, &(&1 + diff))

    next_i = if Enum.at(row_sums, i) == max_sum, do: i + 1, else: i
    next_j = if Enum.at(col_sums, j) == max_sum, do: j + 1, else: j

    balance(rows, row_sums, col_sums, max_sum, next_i, next_j)
  end

  defp balance(rows, row_sums, col_sums, _max_sum, i, j), do: {rows, row_sums, col_sums, i, j}
end

This adjusts the matrix toward a matching target sum so the rows and columns line up more like a magic square.

Elixir Are Equally Strong
defmodule AreEquallyStrong do
  def are_equally_strong(your_left, your_right, friends_left, friends_right) do
    max(your_right, your_left) == max(friends_left, friends_right) and
      min(your_left, your_right) == min(friends_right, friends_left)
  end
end

This compares each person’s strongest and weakest arm. If both pairs match, the result is true.

Elixir Array Change
defmodule ArrayChange do
  def array_change(a) when length(a) < 2, do: 0

  def array_change(a) do
    {_final, total} =
      Enum.reduce(0..(length(a) - 2), {a, 0}, fn k, {arr, total} ->
        cur = Enum.at(arr, k)
        nxt = Enum.at(arr, k + 1)

        if cur >= nxt do
          diff = cur - nxt + 1
          {List.update_at(arr, k + 1, &(&1 + diff)), total + diff}
        else
          {arr, total}
        end
      end)

    total
  end
end

This moves left to right and bumps values only when needed so the array becomes strictly increasing.

Elixir Array Maximal Adjacement Difference
defmodule ArrayMaximalAdjacentDifference do
  def array_maximal_adjacent_difference(a) when length(a) < 3, do: 0

  def array_maximal_adjacent_difference(a) do
    len = length(a)

    1..(len - 2)
    |> Enum.map(fn i ->
      prev = Enum.at(a, i - 1)
      cur = Enum.at(a, i)
      nxt = Enum.at(a, i + 1)
      max(abs(cur - prev), abs(cur - nxt))
    end)
    |> Enum.max()
  end
end

This checks the gap between each pair of neighbors and returns the largest difference.

Elixir Binary Gap
defmodule BinaryGap do
  def binary_gap(n) do
    n
    |> Integer.to_string(2)
    |> String.trim("0")
    |> String.split("1")
    |> Enum.map(&String.length/1)
    |> Enum.max()
  end
end

This turns the number into binary, ignores zeroes outside the edges, and finds the longest run of zeroes between 1s.