In this tutorial I will cover the core syntax of the Elixir language in one video. If you jump to YouTube you’ll find time stamps so you can easily jump to what interests you. You can also use the time stamps so you can watch this video in parts.
I cover Input / Output, Data Types, Strings, Math, Comparison, Decision Making, Tuples, Lists, Maps, Pattern Matching, Anonymous Functions, Recursion, Looping, Enumerables, List Comprehensions, Exception Handling, Concurrency and more.
If you like videos like this consider donating a $1 on Patreon. It helps a lot.
[googleplusone]
Code & Cheat Sheet
# This creates your module which holds all your
# functions
defmodule M do
# Functions start with def, the functions name
# and then end
def main do
# gets retrieves user input
# trim removes the newline
name = IO.gets("What is your name? ")
|> String.trim
# You can combine string and variable output
# with #{}
IO.puts "Hello #{name}"
data_stuff()
end
# ----- DATA TYPES -----
# Variables start with lowercase letters or
# underscores and then uppercase letters,
# underscores or numbers
# Once set a variables value can't change
# Types Integers, Floats, Atoms, Ranges,
# Binaries, Lists, Maps, Tuples
def data_stuff do
# There is no maximum int size
my_int = 123
IO.puts "Integer #{is_integer(my_int)}"
# Floats have about 16 digit precision
my_float = 3.14159
IO.puts "Float #{is_float(my_float)}"
# An Atoms name is its value
IO.puts "Atom #{is_atom(:Pittsburgh)}"
# Use double quotes for spaces
:"New York"
# Ranges define a start and end using ints
one_to_10 = 1..10
# ----- STRINGS -----
# Strings are defined with double quotes
my_str = "My Sentence"
IO.puts "Length : #{String.length(my_str)}"
# You can combine strings
longer_str = my_str <> " " <> "is longer"
# Compare strings
IO.puts "Equal : #{"Egg" === "egg"}"
# Check if a string contains a string
IO.puts "My ? #{String.contains?(my_str, "My")}"
# Return first character
IO.puts "First : #{String.first(my_str)}"
# Get character at index
IO.puts "Index 4 : #{String.at(my_str, 4)}"
# Get a substring
IO.puts "Substring : #{String.slice(my_str, 3, 8)}"
# Split a string into a list
# Inspect which prints the internal
# representation of a value
IO.inspect String.split(longer_str, " ")
# Reverse a string
IO.puts String.reverse(longer_str)
# Uppercase
IO.puts String.upcase(longer_str)
# Lowercase
IO.puts String.downcase(longer_str)
# Capitalize
IO.puts String.capitalize(longer_str)
# Pipe output from one to another
4 * 10 |> IO.puts
# ----- MATH -----
IO.puts "5 + 4 = #{5+4}"
IO.puts "5 - 4 = #{5-4}"
IO.puts "5 * 4 = #{5*4}"
IO.puts "5 / 4 = #{5/4}"
IO.puts "5 div 4 = #{div(5,4)}"
IO.puts "5 rem 4 = #{rem(5,4)}"
# ----- COMPARISON -----
IO.puts "4 == 4.0 : #{4 == 4.0}"
# Checks for equality of value and type
IO.puts "4 === 4.0 : #{4 === 4.0}"
IO.puts "4 != 4.0 : #{4 != 4.0}"
# Checks for inequality of value and type
IO.puts "4 !== 4.0 : #{4 == 4.0}"
IO.puts "5 > 4 : #{5 > 4}"
IO.puts "5 >= 4 : #{5 >= 4}"
IO.puts "5 < 4 : #{5 < 4}"
IO.puts "5 <= 4 : #{5 <= 4}"
# Logical operators
age = 16
IO.puts "Vote & Drive : #{(age >= 16) and (age >= 18)}"
IO.puts "Vote or Drive : #{(age >= 16) or (age >= 18)}"
# Converts true to false vice versa
IO.puts not true
# ----- DECISION MAKING -----
# If and Else
if age >= 18 do
IO.puts "Can Vote"
else
IO.puts "Can Wait"
end
# Unless
unless age === 18 do
IO.puts "You're not 18"
else
IO.puts "You're 18"
end
# Cond works like else if
# it only hits the 1st match
cond do
age >= 14 -> IO.puts "You can wait"
age >= 16 -> IO.puts "You can drive"
age >= 18 -> IO.puts "You can vote"
true -> IO.puts "Default"
end
# Case works like switch
case 2 do
1 -> IO.puts "Entered 1"
2 -> IO.puts "Entered 2"
_ -> IO.puts "Default"
end
# Ternary operator
IO.puts "Ternary : #{if age > 18, do: "Can Vote", else: "Can't Vote"}"
# ----- TUPLES -----
# Tuples normally have 2 to 4 values
# They can hold any value
# They aren't for enumerating, or
# cycling through like lists
# They ar for pattern matching
# Create a tuple
my_stats = {175, 6.25, :Derek}
IO.puts "Tuple #{is_tuple(my_stats)}"
# You can append values
my_stats2 = Tuple.append(my_stats, 42)
# Retrieve values by index
IO.puts "Age #{elem(my_stats2, 3)}"
# Get tuple size
IO.puts "Size #{tuple_size(my_stats2)}"
# Delete an index
my_stats3 = Tuple.delete_at(my_stats2, 0)
# Insert at an index
my_stats4 = Tuple.insert_at(my_stats3, 0, 1974)
# Create a tuple with the same values
# duplicated a number of times
many_zeroes = Tuple.duplicate(0, 5)
# You can use tuples for pattern matching
{weight, height, name} = {175, 6.25, :Derek}
IO.puts "Weight : #{weight}"
# ----- LISTS -----
# Lists contain lists of data of any data type
list1 = [1,2,3]
list2 = [4,5,6]
# You can combine Lists
list3 = list1 ++ list2
# You can subtract Lists
list4 = list3 -- list1
# Verify if an item is in a list
IO.puts 6 in list4
# Separate the head and tail of list
[head | tail] = list3
IO.puts "Head : #{head}"
# Write to the screen without a newline
IO.write "Tail : "
# To show the tail use inspect
IO.inspect tail
# Inspect which prints the internal
# representation of a
# value may give odd results
IO.inspect [97,98]
# You can force inspect to print as a list
# like this
IO.inspect [97,98], char_lists: :as_lists
# Enum can enumerate over lists
Enum.each tail, fn item ->
IO.puts item
end
words = ["Random", "Words", "in a", "list"]
Enum.each words, fn word ->
IO.puts word
end
# We can use recursion to loop as well
display_list(words)
# Delete deletes the given item from a list
IO.puts display_list(List.delete(words,"Random"))
# Delete item at index
IO.puts display_list(List.delete_at(words,1))
# Insert item at index
IO.puts display_list(List.insert_at(words,4, "Yeah"))
# Get first item
IO.puts List.first(words)
# Get last item
IO.puts List.last(words)
# You can create lists of key value tuples
my_stats5 = [name: "Derek", height: 6.25, weight: 175]
# ----- MAPS -----
# Maps hold collections of key value pairs
capitals = %{"Alabama" => "Montgomery",
"Alaska" => "Juneau", "Arizona" => "Phoenix"}
# Retrieve values using the key
IO.puts "Capital of Alaska is #{capitals["Alaska"]}"
# You can use atoms as keys
capitals2 = %{alabama: "Montgomery",
alaska: "Juneau", arizona: "Phoenix"}
IO.puts "Capital of Arizona is #{capitals2.arizona}"
# Insert a key / value
capitals3 = Dict.put_new(capitals, "Arkansas", "Big Rock")
# ----- PATTERN MATCHING -----
# With pattern matching we can retrieve
# data from data structures
[length, width] = [20, 30]
IO.puts "Width : #{width}"
# If you don't care about data use _
[_, [_, a]] = [20, [30, 40]]
IO.puts "Get Num : #{a}"
# ----- ANONYMOUS FUNCTIONS -----
# An anonymous function has no name and can
# be passed to another function
get_sum = fn (x, y) -> x + y end
IO.puts "5 + 5 = #{get_sum.(5,5)}"
# Shorthand of th above
# Increment the parameter names by 1
get_less = &(&1 - &2)
IO.puts "7 - 6 = #{get_less.(7,6)}"
# You can have functions except different
# numbers of parameters
add_sum = fn
{x,y} -> IO.puts "#{x} + #{y} = #{x+y}"
{x,y,z} -> IO.puts "#{x} + #{y} + #{z} = #{x+y+z}"
end
add_sum.({1,2})
add_sum.({1,2,3})
# You can set defaults for parameters
IO.puts do_it()
# ----- RECURSION -----
# Recursion is the act of a function
# calling itself
IO.puts "Factorial of 3 : #{factorial(4)}"
# ----- LOOPING -----
# With most languages we loop by
# incrementing or decrementing a value
# Since all variables are immutable
# in Elixir we use recursion to loop
IO.puts "Sum : #{sum([1,2,3])}"
# An Elixir for loop
loop(5,1)
# ----- ENUMERABLES -----
# An enumerable can have its items
# counted off
# Check if all values are even
IO.puts "Even List : #{Enum.all?([1,2,3],
fn(n) -> rem(n,2) == 0 end)}"
# Check if any items are even
IO.puts "Even Item : #{Enum.any?([1,2,3],
fn(n) -> rem(n,2) == 0 end)}"
# Print out each item
Enum.each([1,2,3], fn(n) -> IO.puts n end)
# Double each value in a list
dbl_list = Enum.map([1,2,3], fn(n) -> n * 2 end)
IO.inspect dbl_list
# Reduce down to a single value
sum_vals = Enum.reduce([1,2,3], fn(n, sum) -> n + sum end)
IO.puts "Sum : #{sum_vals}"
IO.inspect Enum.uniq([1,2,2])
# ----- LIST COMPREHENSIONS -----
# Provides an additonal way to perform
# actions on a list
# Double every list item
dbl_list2 = for n <- [1,2,3], do: n * 2
IO.inspect dbl_list2
# Create a list of evens
even_list = for n <- [1,2,3,4], rem(n,2) == 0, do: n
IO.inspect even_list
# ----- EXCEPTION HANDLING -----
# Allows us to handle errors
err = try do
5 / 0
rescue
ArithmeticError -> "Can't Divide by Zero"
end
IO.puts err
# ----- CONCURRENCY -----
# Running multiple blocks of code at once
# Calling spawn starts a new process that
# runs the code specified at an undefined
# time
# Spawn returns a Process ID (PID)
spawn(fn() -> loop(50, 1) end)
spawn(fn() -> loop(100, 50) end)
# We can send messgaes between
# processes
# Send a message to this process
# and receive it
send(self(), {:french, "Bob"})
receive do
{:german, name} -> IO.puts "Guten tag #{name}"
{:french, name} -> IO.puts "Bonjour #{name}"
{:english, name} -> IO.puts "Hello #{name}"
# If there is no matching message you can issue
# a timeout like I did for 500 milliseconds
after
500 -> IO.puts "Times up"
end
end
# ----- RECURSIVE FUNCTIONS -----
# Output list with recursion
def display_list([word|words]) do
IO.puts word
display_list(words)
end
def display_list([]), do: nil
# Calculate a factorial
def factorial(num) do
# This will end the calling of
# additional functions
if num <= 1 do
1
else
result = num * factorial(num - 1)
result
end
end
# 1st : result = 4 * factorial(3) = 4 * 6 = 24
# 2nd : result = 3 * factorial(2) = 3 * 2 = 6
# 3rd : result = 2 * factorial(1) = 2 * 1 = 2
# Demonstrate looping
# Sum values in a list
# Decide what happens if we get an empty list
def sum([]), do: 0
# Empty the list as we sum values
def sum([h|t]), do: h + sum(t)
# A Elixir for loop
# What happens if the 1st attribute is 0
def loop(0,_), do: nil
def loop(max, min) do
if max < min do
loop(0, min)
else
IO.puts "Num : #{max}"
loop(max - 1, min)
end
end
# ----- DEFINE DEFAULTS -----
# Define defaults with \\
def do_it(x \\ 1, y \\ 1) do
x + y
end
end