Write your first Elixir program: a tip calculator that handles edge cases and splits bills perfectly.
The Magic Calculator
You know what's annoying? Splitting a shared expense among teammates.
"The total is $127.43 including tax, and we need to add 18% service fee, and there are 5 of us, but Sarah only used $15 worth of supplies..."
Your phone's calculator wasn't built for this. But Elixir was.
In this chapter, you'll build a tip calculator that handles all the weird edge cases. By the end, you'll have written actual Elixir code that solves a real problem.
Our Goal
We want a calculator that:
- Takes a bill amount
- Adds a tip percentage
- Splits it evenly (or handles "Sarah only used $15 worth of supplies")
- Shows exactly what each person pays
Creating Your First Elixir File
Elixir files end with .ex (for compiled code) or .exs (for scripts we'll run once).
Step 1: Create a new folder for your code:
- Open your terminal/command prompt
- Navigate to where you want your code (Desktop, Documents, wherever)
- Create a folder:
mkdir elixir_projects
cd elixir_projectsStep 2: Create a file called tip_calculator.exs:
- macOS/Linux:
touch tip_calculator.exs - Windows:
type nul > tip_calculator.exs
Or just use your text editor (VS Code, Sublime, Notepad, whatever) and save an empty file as tip_calculator.exs.
Step 3: Open the file in your editor.
Writing the Basic Calculator
Type this into your file:
# Tip Calculator - Your First Elixir Program
defmodule TipCalculator do
def calculate(bill_amount, tip_percent, people_count) do
tip_amount = bill_amount * (tip_percent / 100)
total = bill_amount + tip_amount
per_person = total / people_count
per_person
end
end
# Try it out
result = TipCalculator.calculate(100, 20, 4)
IO.puts("Each person pays: $#{result}")Don't worry about what everything means yet. We'll break it down.
Running Your Program
In your terminal (in the same folder as your file):
elixir tip_calculator.exsYou should see:
Each person pays: $30.0Congratulations! You just wrote and ran your first Elixir program.
Breaking Down the Code
Let's understand what we wrote:
defmodule TipCalculator do
A module is like a container for related code. We named ours TipCalculator because that's what it does.
Think of it like labeling a folder: "This folder contains everything about calculating tips."
def calculate(bill_amount, tip_percent, people_count) do
This defines a function called calculate. Functions are reusable pieces of code.
Our function takes three arguments (inputs):
bill_amount- How much the bill istip_percent- What percentage to tippeople_count- How many people are splitting
The Math
tip_amount = bill_amount * (tip_percent / 100)This calculates the tip. If the bill is $100 and tip is 20%, this gives us $20.
total = bill_amount + tip_amountAdds the tip to the bill.
per_person = total / people_countSplits the total among everyone.
end
Every do needs an end. This closes the function and the module.
IO.puts("Each person pays: $#{result}")
This prints output to the screen. The #{result} part inserts our calculated value into the string.
Making It Better: Handling Edge Cases
Our calculator works, but it's basic. Let's handle real-world messiness.
Problem 1: Rounding to 2 decimal places (cents)
Update your function:
def calculate(bill_amount, tip_percent, people_count) do
tip_amount = bill_amount * (tip_percent / 100)
total = bill_amount + tip_amount
per_person = total / people_count
# Round to 2 decimal places for cents
Float.round(per_person, 2)
endNow try:
result = TipCalculator.calculate(127.43, 18, 5)
IO.puts("Each person pays: $#{result}")Problem 2: What if someone pays a different amount?
Let's add a function for uneven splits:
defmodule TipCalculator do
def calculate(bill_amount, tip_percent, people_count) do
tip_amount = bill_amount * (tip_percent / 100)
total = bill_amount + tip_amount
per_person = total / people_count
Float.round(per_person, 2)
end
def calculate_uneven(bill_amount, tip_percent, individual_amounts) do
tip_amount = bill_amount * (tip_percent / 100)
total_tip_per_dollar = tip_amount / bill_amount
Enum.map(individual_amounts, fn amount ->
their_tip = amount * total_tip_per_dollar
their_total = amount + their_tip
Float.round(their_total, 2)
end)
end
end
# Even split
result = TipCalculator.calculate(100, 20, 4)
IO.puts("Even split - Each pays: $#{result}")
# Uneven split (Sarah only spent $15 on supplies)
amounts = [35, 28, 42, 15, 30] # What each person used
results = TipCalculator.calculate_uneven(150, 18, amounts)
IO.puts("\nUneven split:")
Enum.with_index(results, 1) |>
Enum.each(fn {amount, index} ->
IO.puts("Person #{index} pays: $#{amount}")
end)Run it:
elixir tip_calculator.exsWhat Just Happened?
We used several new things:
Enum.map - Takes a list and transforms each item
fn amount -> ... end - An anonymous function (we'll cover this more later)
|> (the pipe operator) - Takes the result of one thing and passes it to the next
Enum.with_index - Gives us each item plus its position (starting at 1)
Enum.each - Does something for each item (in this case, printing)
Don't worry if this feels overwhelming. You're seeing the future—you'll understand all of this soon.
A Complete Example
Here's a polished version with helpful output:
defmodule TipCalculator do
def split_bill(bill_amount, tip_percent, people) when is_integer(people) do
tip_amount = bill_amount * (tip_percent / 100)
total = bill_amount + tip_amount
per_person = total / people
IO.puts("Bill: $#{bill_amount}")
IO.puts("Tip (#{tip_percent}%): $#{Float.round(tip_amount, 2)}")
IO.puts("Total: $#{Float.round(total, 2)}")
IO.puts("Split #{people} ways: $#{Float.round(per_person, 2)} each")
Float.round(per_person, 2)
end
def split_bill(bill_amount, tip_percent, individual_orders) when is_list(individual_orders) do
tip_amount = bill_amount * (tip_percent / 100)
tip_ratio = tip_amount / bill_amount
IO.puts("Bill: $#{bill_amount}")
IO.puts("Tip (#{tip_percent}%): $#{Float.round(tip_amount, 2)}")
IO.puts("Individual totals:")
Enum.with_index(individual_orders, 1)
|> Enum.each(fn {order_amount, index} ->
their_tip = order_amount * tip_ratio
their_total = order_amount + their_tip
IO.puts(" Person #{index}: $#{Float.round(their_total, 2)}")
end)
end
end
# Example 1: Even split among friends
TipCalculator.split_bill(127.43, 18, 5)
IO.puts("\n---\n")
# Example 2: Everyone ordered different amounts
orders = [45.50, 32.00, 28.50, 21.43]
TipCalculator.split_bill(127.43, 18, orders)What You Learned
Even though this was your first program, you already used:
- Modules (
defmodule) - containers for code - Functions (
def) - reusable pieces of logic - Variables (
bill_amount,tip_amount) - storing values - Math operators (
+,-,*,/) - Lists (
[45.50, 32.00, ...]) - Pattern matching with guards (
when is_integer,when is_list) - The pipe operator (
|>)
Not bad for your first day!
Try It Yourself
- Modify the calculator to include tax calculation (add a tax_percent parameter)
- Make it round up to the nearest dollar for easier bill splitting
- Add a function that calculates just the tip amount
Remember: Breaking things is how you learn. If you get an error, read it carefully—it usually tells you exactly what went wrong.
What we just learned:
- Elixir code goes in
.exsfiles (for scripts) or.exfiles (for compiled programs) - Functions live inside modules
- Variables store values using
= - The pipe operator
|>chains operations together - You can have multiple functions with the same name if they do different things
Up next: Getting help when you're stuck (spoiler: the Elixir community is incredibly friendly).