Learn Erlang in One Video

Learn Erlang in One VideoIn this tutorial I’m going to teach the core syntax of the Erlang language with many examples. This video is for someone that already knows another language and wants to translate common programming syntax into Erlang.

If you jump to YouTube in the description you’ll find time stamps to every main part of the video. For best results take notes on the cheat sheet provided below as you watch and leave any questions you have.

If you value videos like this consider donating a $1 on Patreon

[googleplusone]

Code & Cheat Sheet

-module(erlangtut).

-export([hello_world/0]).

hello_world() -> io:fwrite("hello, world\n").

cd("/Users/derekbanas/Documents/workspace/ErlangTut/src").

c(erlangtut).
erlangtut:hello_world().

cd("C:\Users\derekbanas\workspace\ErlangTut\src").

% @author derekbanas
% @doc @todo Add description to erlangtut.

% ----- BASICS -----

% Modules contain many functions
% This will always be the first statement in a file
% because it defines the module

% We compile to byte code like this c(tut).

-module(tut).

% Import string functions
-import(string, [len/1, concat/2, chr/2, substr/3, str/2, 
				 to_lower/1, to_upper/1]).

% Defines what functions can be called from this module
% /0 defines that this function doesn't receive attributes
% /2 defines that add recieves 2
% -export([hello_world/0, add/2, add/3, main/0]).
-export([main/0]).

% We execute functions like this tut:hello_world().
% fwrite outputs a string to the console
hello_world() -> 
	io:fwrite("Hello World\n").

% Recieve 2 values and return the sum
add(A, B) -> 
	% You can call other functions
	% Separate multiple statements with a comma
	hello_world(),
	A + B.

% You can define functions with the same name
% as long as the number of attributes differ
add(A, B, C) ->
	A + B + C.

% tut:module_info(). gives you info on your module

% ----- VARIABLES -----

% Variable names start with an uppercase letter
% or _ and then letters, numbers, _, or @
% A variables value cannot change
% A variables type is defined dynamically

% You can call a function before it was created
% Even if you call multiple functions only
% output from the last shows
main() ->
	var_stuff(),
	atom_stuff(),
	do_math(5,4),
	compare(4,4.0),
	what_grade(10),
	say_hello(german),
	string_stuff(),
	tuple_stuff(),
	list_stuff(),
	lc_stuff(),
	type_stuff(),
	find_factorial(3),
	sum([1,2,3]),
	sum2([1,2,3], 0),
	for(3,1),
	map_stuff(),
	record_stuff(),
	do_math2(),
	fun_stuff("Derek"),
	fun_stuff2(),
	write_txt("Write to the file"),
	write_txt2(" More text for the file"),
	read_txt(),
	error_stuff(0),
	read_txt2(),
	macro_stuff(5,6),
	spawner(),
	spawner(),
	spawner2(50,1),
	spawner2(100, 51).

var_stuff() ->
	Num = 1,
	Num.

% An Atom is variable thats name equals its value
% They start with lowercase letters, or are 
% surrounded by single quotes
atom_stuff() ->
	'An Atom'.

% ----- MATH -----
do_math(A, B) ->
	A + B,
	A - B,
	A * B,
	
	% Float division
	A / B,
	
	% Integer division
	A div B,

	% Modulus returns the remainder
	A rem B,
	
	% e raised to the X power
	math:exp(1),
	
	% Natural log
	math:log(2.71828),
	
	% Common log
	math:log10(1000),
	
	% Power
	math:pow(10,2),

	% Square root
	math:sqrt(100),

	% There is also sin, cos, tan, asin, acos, atan,
	% sinh, cosh, tanh, asinh, acosh, atanh

	% Generate random number from 1 to 10
	random:uniform(10).

% ----- COMPARING VALUES -----
% You receive true or fale from comparisons
% 0 isn't equal to false
compare(A, B) ->
	% Check for equality of value and type
	A =:= B,
	
	% Check for inequality of value and type
	A =/= B,

	% Disregard type
	A == B,
	
	% Disregard type
	A /= B,
	
	% >, <, >=, =<, and, or, not, xor
    Age = 18,
	(Age >= 5) or (Age =< 18).

% ----- IF CONDITIONALS -----
% If is used to perform different actions
% based on conditions
preschool() ->
	'Go to preschool'.

kindergarten() ->
	'Go to kindergarten'.

grade_school() ->
	'Go to grade school'.

what_grade(X) ->
	if X < 5 -> preschool()
	; X == 5 -> kindergarten()
	; X > 5 -> grade_school()
	end.

% ----- CASE CONDITIONALS -----
% Case performs different actions based on values
say_hello(X) ->
	case X of
		french -> 'Bonjour';
		german -> 'Guten Tag';
		english -> 'Hello'
	end.

% ----- STRINGS -----
% Strings must be surrounded by double quotes

string_stuff() ->
	Str1 = "Random string",
	Str2 = "Another string",
	
	% You can place strings or any data in
	% output using ~p
	io:fwrite("String : ~p ~p\n", [Str1, Str2]),
	
	% format can be used for similar results
	Str3 = io_lib:format("It's a ~s and ~s\n", [Str1, Str2]),
	io:fwrite(Str3),
	
	% Get string length
	len(Str3),

	% Concatenate strings
	Str4 = concat(Str1, Str2),
	Str4,
	
	% Get index for character
	CharIndex = chr(Str4, $n),
	CharIndex,
	
	% Return string start at index and number
	% of characters
	Str5 = substr(Str4, 8, 6),
	Str5,
	
	% Get index of string
	StrIndex = str(Str4, Str2),
	StrIndex,
	
	% All uppercase
	to_upper(Str1),
	
	% All lowercase
	to_lower(Str1).

% ----- TUPLES -----
% A Tuple can hold multiple values

tuple_stuff() ->
	My_Data = {42, 175, 6.25},
	
	% Get all values
	My_Data,
	
	% Store values in another tuple
	{A,B,C} = My_Data,
	
	% Return just 1 value
	C,
	
	% Use an anonymous variable to match a pattern
	{D,_,_} = My_Data,
	D,

	% You can use an Atom as the key for a value
	% Tagged Tuple
	My_Data_2 = {height, 6.25},
	{height, Ht} = My_Data_2,
	Ht.

% ----- LISTS -----
% Lists contain multiple values from any 
% data type

list_stuff() ->
	List1 = [1,2,3],
	List2 = [4,5,6],
	
	% Join lists with ++
	List3 = List1 ++ List2,
	List3,

	% Subtract a list
	List4 = List3 -- List1,
	List4,
	
	% Retrieve the 1st element (Head)
	hd(List4),
	
	% Retrieve all but the first (Tail)
	tl(List4),
	
	% Add a value to the list with the cons operator
	List5 = [3|List4],
	List5,
	
	% Get the head and tail
	[Head|Tail] = List5,
	Head.

% ----- LIST COMPREHENSIONS -----
% List comprehensions make it easy to manipulate lists

lc_stuff() ->
	List1 = [1,2,3],
	
	% Multiply every list item times 2
	% N is an incrementing list item
	List2 = [2*N || N <- List1],
	List2,
	
	% You can add conditions like to get only evens
	List3 = [1,2,3,4],
	List4 = [N || N <- List3, N rem 2 == 0],
	List4,

	% Search through a list of tuples for perfect weather
	City_Weather = [{pittsburgh, 50}, {'new york', 53}, 
					{charlotte, 68}, {miami, 78}],
	Great_Temp = [{City, Temp} || {City, Temp} <- City_Weather, Temp >= 50],
	Great_Temp.

% ----- TYPE CONVERSIONS -----
type_stuff() ->
	% You can check the type of a variable
	is_atom(name),
	is_float(3.14),
	is_integer(10),
	is_boolean(false),
	is_list([1,2,3]),
	is_tuple({height, 6.24}),

	% You can convert from one to another using
	% type_to_type
	% atom_to_binary, atom_to_list, binary_to_atom, 
	% binary_to_list, bitstring_to_list, binary_to_term, 
	% float_to_list, fun_to_list, integer_to_list, 
	% integer_to_list, iolist_to_binary, iolist_to_atom, 
	% list_to_atom, list_to_binary, list_to_bitstring, 
	% list_to_float, list_to_integer, list_to_pid, 
	% list_to_tuple, pid_to_list, port_to_list, ref_to_list, 
	% term_to_binary, term_to_binary, tuple_to_list
	List1 = integer_to_list(21),
	List1.

% ----- RECURSION -----
% Recursion is the act of a function calling itself
% Those things you normally accomplish with looping
% in other languages are done using recursion 
% with Erlang

% We can use recursion to find the factorial

factorial(N) when N == 0 -> 1;
factorial(N) when N > 0 -> N * factorial(N - 1).

find_factorial(X) ->
	Y = factorial(X),
	io:fwrite("Factorial : ~p\n", [Y]).

% 1st: 3 -> 3 * f(2) == 3 * 2 = 6
% 2nd: 2 -> 2 * f(1) == 2 * 1 (Send Above)
% 3rd: 1 -> 1 * f(0) == 1 * 1 (Send Above)

% Sum a list

sum([]) -> 0;
sum([H|T]) -> H + sum(T).

% sum([1,2,3])
% 1 + sum([2,3])
% 1 + 2 + sum([3])
% 1 + 2 + 3 + sum([])

% Tail Recursive
% Instead of holding up the additions
% we can keep a running count

sum2([], Sum) -> Sum;
sum2([H|T], Sum) -> 
	io:fwrite("Sum : ~p\n", [Sum]),
	sum2(T, H + Sum).

% sum2([1,2,3], 0)
% sum2([2,3], 1)
% sum2([3], 3)
% sum2([], 6)

% You can create a for loop with recursion
for(0,_) -> 
   ok; 
   
for(Max,Min) when Max > 0 -> 
   io:fwrite("Num : ~p\n", [Max]), 
   for(Max-1,Min). 
   
% for(3,1) Num : 3
% for(2,1) Num : 2
% for(1,1) Num : 1
% for(0,1) End

% ----- MAPS -----
% A Map is a group of key value pairs

map_stuff() ->
	Bob = #{f_name=>'Bob', l_name=>'Smith'},
	
	% Get value assigned to a key
	io:fwrite("1st Name : ~p\n",[maps:get(f_name, Bob)]),
	
	% Get all keys
	io:fwrite("~p\n", [maps:keys(Bob)]),
	
	% Get all values
	io:fwrite("~p\n", [maps:values(Bob)]),
	
	% Return everything except the key designated
	io:fwrite("~p\n", [maps:remove(l_name, Bob)]),
	
	% Check if a key exists
	maps:find(f_name, Bob),
	
	% Add a key value to the map
	maps:put(address, "123 Main", Bob).

% ----- RECORDS -----
% You can define a custom type that contains
% multiple fields

-record(customer, {name = "", bal = 0.00}).

record_stuff() ->
	
	% Define a customer
	Sally = #customer{name="Sally Smith", bal=100.00},
	
	% Change data
	Sally2 = Sally#customer{bal = 50},
	
	% Output data
	io:fwrite("~p owes $ ~p\n", [Sally2#customer.name, 
							 Sally2#customer.bal]).

% ----- HIGHER ORDER FUNCTIONS -----
% Functions that can receive other functions as
% a parameter is known as a higher order function

% Define a function that multiplies
% every item by 2
double(X) -> X * 2.

% This one triples the number
triple(X) -> X * 3.

% lists:map takes a function and applies
% that function to every item in the list

% Fun is used to assign a function
% to a variable
do_math2() -> 
	lists:map(fun double/1, [1,2,3]),
	lists:map(fun triple/1, [1,2,3]).

% You can use fun to define anonymous functions
fun_stuff(N) ->
	Fun_Stuff = fun() -> io:fwrite("Hello ~p\n",[N]) end,
	Fun_Stuff().

% You can also access values outside of the function
fun_stuff2() ->
	X = 3,
	Y = 4,
	Z = fun() ->
				io:fwrite("Sum : ~p\n",[X + Y]) end,
	Z().

% ----- FILE I/O -----
% Create and write to a file
write_txt(N) ->
	% Get file handler and write
	{ok, Fh} = file:open("MyFile.txt", [write]),
	
	% Write the text
	file:write(Fh, N).

write_txt2(N) ->
	% Get file handler and append
	{ok, Fh} = file:open("MyFile.txt", [append]),
	
	file:write(Fh, N).

% Read from file
read_txt() ->
	% Get read permission
	{ok, File} = file:open("MyFile.txt", [read]),
	
	% Read text from file
	Words = file:read(File, 1024 * 1024),
	io:fwrite("~p\n", [Words]).

% ----- EXCEPTION HANDLING -----
% Exception handling allows our program to
% handle errors rather then just crashing

% You place code that could crash after 
% try and then list what happens when certain
% errors occur after catch
error_stuff(N) ->
	try
		Ans = 2 / N,
		Ans
	catch
		error:badarith ->
			"Can't divide by zero"
	end.

read_txt2() ->
	try
		{ok, File} = file:open("MyFile1.txt", [read]),
		Words = file:read(File, 1024 * 1024),
		io:fwrite("~p\n", [Words])
	catch
		% This will catch all errors
		_:_ ->
			"File Doesn't Exist"
	end.

% ----- MACROS -----
% Macros provide for inline code replacement

% Define the constant and what replaces it
-define(add(X,Y), {X+Y}).

macro_stuff(X,Y) ->
	
	% ? defines to use the macro
	io:fwrite("~p\n", [?add(X,Y)]).

% ----- CONCURRENCY -----
% Concurrency is the when several processes
% execute at the same time and potentially
% interact

% As long as the processes aren't dependent
% on each other they can run at the same time
% Count to 1 million, calculate Pi aren't dependent
% but start engine drive car are

get_id(M) ->
	io:fwrite("ID : ~p\n", [M]).

% You can generate a process and define the function
% to execute. This passes the process ID
spawner() ->
	spawn(fun() -> get_id([self()]) end).

% Create a for loop that counts using different
% ranges
for2(0,_) -> 
   ok; 
   
for2(Max,Min) when Max > 0 -> 
   io:fwrite("Num : ~p\n", [Max]), 
   for(Max-1,Min). 

% The process take turns doing their jobs
spawner2(Max, Min) ->
	spawn(fun() -> for2(Max, Min) end).

Leave a Reply

Your email address will not be published. Required fields are marked *