SlideShare ist ein Scribd-Unternehmen logo
1 von 175
Downloaden Sie, um offline zu lesen
Pre-bootcamp
introduction to Elixir
Paweł Dawczak
# 1. Introduction - what is Elixir, how to start?
# 2. Basic and compound data types
# 3. Functions and modules
# 4. Let’s talk about `=`
# 5. Let’s have some fun!
# 6. Let’s talk about `mix`
# 7. Let’s talk about dependencies
# 8. Suggestions where to find more information
# 9. QA
# What is Elixir?
# Background
JVM
BEAM
Erlang/OTP
O
T
P
Erlang/OTP
O - Open
T - Telecom
P - Platform
José Valim
-module(my_module).
-export([hello/1]).
hello(Str) ->
my_helper(Str).
my_helper(Str) ->
string:reverse(string:uppercase(Str)).
-module(my_module).
-export([hello/1]).
hello(Str) ->
my_helper(Str).
my_helper(Str) ->
string:reverse(string:uppercase(Str)).
defmodule MyModule do
def hello(str) do
my_helper(str)
end
defp my_helper(str) do
str
|> String.upcase()
|> String.reverse()
end
end
# Where do I start?
# Install erlang
$ asdf plugin-add erlang
$ asdf list-all erlang # will list all the available versions
$ asdf install erlang 20.3.7
$ asdf global erlang 20.3.7
# Install erlang
$ asdf plugin-add erlang
$ asdf list-all erlang # will list all the available versions
$ asdf install erlang 20.3.7
$ asdf global erlang 20.3.7
# Install Elixir
$ asdf plugin-add elixir
$ asdf list-all elixir
$ asdf install elixir 1.6.5
$ asdf global elixir 1.6.5
# Install erlang
$ asdf plugin-add erlang
$ asdf list-all erlang # will list all the available versions
$ asdf install erlang 20.3.7
$ asdf global erlang 20.3.7
# Install Elixir
$ asdf plugin-add elixir
$ asdf list-all elixir
$ asdf install elixir 1.6.5
$ asdf global elixir 1.6.5
# [Optional] Install Node
# Basic data types
nil # => nil
true # => true
:test # => :test
nil # => nil
true # => true
:test # => :test
1 # => 1
1.2 # => 1.2
"Testing" # => "Testing"
'Testing' # => 'Testing'
nil # => nil
true # => true
:test # => :test
1 # => 1
1.2 # => 1.2
"Testing" # => "Testing"
'Testing' # => 'Testing'
is_binary("Testing") # => true
is_binary('Testing') # => false
is_list("Testing") # => false
is_list('Testing') # => true
nil # => nil
true # => true
:test # => :test
1 # => 1
1.2 # => 1.2
"Testing" # => "Testing"
'Testing' # => 'Testing'
is_binary("Testing") # => true
is_binary('Testing') # => false
is_list("Testing") # => false
is_list('Testing') # => true
pid(0, 13, 0) # => #PID<0.13.0>
nil # => nil
true # => true
:test # => :test
1 # => 1
1.2 # => 1.2
"Testing" # => "Testing"
'Testing' # => 'Testing'
is_binary("Testing") # => true
is_binary('Testing') # => false
is_list("Testing") # => false
is_list('Testing') # => true
pid(0, 13, 0) # => #PID<0.13.0>
make_ref() # => #Reference<0.1816712181.2865233921.217076>
# The reference is unique among connected nodes.
# Compound data types
# Lists
[1, 2, 3] # => [1, 2, 3]
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Structs
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Structs
defmodule User do
end
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Structs
defmodule User do
defstruct [:first_name, :last_name, username: "Guest"]
end
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Structs
defmodule User do
defstruct [:first_name, :last_name, username: "Guest"]
end
%User{first_name: "Pawel", last_name: "Dawczak"}
# Lists
[1, 2, 3] # => [1, 2, 3]
# Tuples
{:ok, "Test"} # => {:ok, "Test"}
# Maps
map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"}
map[:first_name] # => "Pawel"
# Keyword Lists
opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
opts[:per_page] # => 3
Keyword.get_values(opts, :per_page) # => [3, 5]
# Structs
defmodule User do
defstruct [:first_name, :last_name, username: "Guest"]
end
%User{first_name: "Pawel", last_name: "Dawczak"}
# => User{first_name: "Pawel", last_name: "Dawczak", username: "Guest"}
# Functions and modules
# Functions
inc = fn x -> x + 1 end
inc.(3) # => 4
# Functions
inc = fn x -> x + 1 end
inc.(3) # => 4
# Capture operator
dec = &(&1 - 1)
dec.(3) # => 2
# Functions
inc = fn x -> x + 1 end
inc.(3) # => 4
# Capture operator
dec = &(&1 - 1)
dec.(3) # => 2
# Modules
defmodule MyModule do
end
# Functions
inc = fn x -> x + 1 end
inc.(3) # => 4
# Capture operator
dec = &(&1 - 1)
dec.(3) # => 2
# Modules
defmodule MyModule do
def square(x) do
x * 2
end
end
MyModule.square(4) # => 8
# Functions
inc = fn x -> x + 1 end
inc.(3) # => 4
# Capture operator
dec = &(&1 - 1)
dec.(3) # => 2
# Modules
defmodule MyModule do
def square(x) do
x * 2
end
def multi(x, y), do: x * y
end
MyModule.square(4) # => 8
MyModule.multi(3, 4) # => 12
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
Enum.reduce(1..3, 0, &+/2) # => 6
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
Enum.reduce(1..3, 0, &+/2) # => 6
pass = "MySecretPass123"
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
Enum.reduce(1..3, 0, &+/2) # => 6
pass = "MySecretPass123"
Enum.map([3, 8, 14], fn x -> String.at(pass, x) end) # => ["e", "P", "3"]
# Comprehensions
for x <- (1..5),
y <- [:blue, :red],
rem(x, 2) == 0,
do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
# Higher-order functions
Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
Enum.reduce(1..3, 0, &+/2) # => 6
pass = "MySecretPass123"
Enum.map([3, 8, 14], fn x -> String.at(pass, x) end) # => ["e", "P", "3"]
Enum.map([3, 8, 14], &String.at(pass, &1)) # => ["e", "P", "3"]
# Let’s talk about `=`
x = 1
1 = x
2 = x
** (MatchError) no match of right hand side value: 1
^x = 1 # ^ - pin operator
^x = 2
list = [20, 21, 22]
[a, b, c] = list
a # => 20
b # => 21
[a, ^x, c] = list
** (MatchError) no match of right hand side value: [20, 21, 22]
hd(list) # => 20
tl(list) # => [21, 22]
[head | tail] = list
head # => 20
tail # => [21, 22]
[a2, 21 | tail] = list
a2 # => 20
tail # => [22]
map = %{a: "Foo", b: "Bar"}
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
end
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
p = %Employee{name: "Pawel", lang: "Elixir"}
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
p = %Employee{name: "Pawel", lang: "Elixir"}
%{name: name} = p
name # => "Pawel"
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
p = %Employee{name: "Pawel", lang: "Elixir"}
%{name: name} = p
name # => "Pawel"
%Employee{name: name} = p
name # => "Pawel"
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
p = %Employee{name: "Pawel", lang: "Elixir"}
%{name: name} = p
name # => "Pawel"
%Employee{name: name} = p
name # => "Pawel"
lang = "Elixir"
map = %{a: "Foo", b: "Bar"}
%{a: a} = map
a # => "Foo"
%{a: "Baz", b: b} = map
** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
defmodule Employee do
defstruct [:name, :lang]
end
p = %Employee{name: "Pawel", lang: "Elixir"}
%{name: name} = p
name # => "Pawel"
%Employee{name: name} = p
name # => "Pawel"
lang = "Elixir"
%Employee{name: name, lang: ^lang} = p
name # => "Pawel"
File.read("./nice_file")
File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
File.read("./non_existing_one") # => {:error, :enoent}
File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
File.read("./non_existing_one") # => {:error, :enoent}
File.read!("./non_existing_one")
** (File.Error) could not read file "./non_existing_one": no such file or directory
File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
File.read("./non_existing_one") # => {:error, :enoent}
File.read!("./non_existing_one")
** (File.Error) could not read file "./non_existing_one": no such file or directory
HTTPoison.get("https://google.com")
File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
File.read("./non_existing_one") # => {:error, :enoent}
File.read!("./non_existing_one")
** (File.Error) could not read file "./non_existing_one": no such file or directory
HTTPoison.get("https://google.com")
{:ok,
%HTTPoison.Response{
body: "...",
headers: [
{"Location", "https://www.google.com/"},
{"Content-Type", "text/html; charset=UTF-8"},
{"Cache-Control", "public, max-age=2592000"},
{"Server", "gws"},
{"Content-Length", "220"},
{"X-Frame-Options", "SAMEORIGIN"},
],
request_url: "https://google.com",
status_code: 301
}}
String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_"))))
String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_"))))
# Pipe operator
String.replace("My Content - 1", ~r/W/, "_")
|> format.()
|> String.upcase()
|> String.reverse()
String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_"))))
# Pipe operator
String.replace("My Content - 1", ~r/W/, "_")
|> format.()
|> String.upcase()
|> String.reverse()
# Pipe operator in action
String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_"))))
# Pipe operator
String.replace("My Content - 1", ~r/W/, "_")
|> format.()
|> String.upcase()
|> String.reverse()
# Pipe operator in action
process = fn
{:ok, %{body: body}} ->
# parse the body, etc…
{:error, error_message} ->
Logger.error("Request failed due to: #{error_message}")
end
String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_"))))
# Pipe operator
String.replace("My Content - 1", ~r/W/, "_")
|> format.()
|> String.upcase()
|> String.reverse()
# Pipe operator in action
process = fn
{:ok, %{body: body}} ->
# parse the body, etc…
{:error, error_message} ->
Logger.error("Request failed due to: #{error_message}")
end
"https://google.com"
|> HTTPoison.get()
|> process.()
# Let the fun begin!
# 1. Fibonacci!
# 1. Fibonacci!
defmodule Fib do
def of(0), do: 1
def of(1), do: 1
def of(n) when n > 1, do: of(n-1) + of(n-2)
end
Fib.of(5)
Fib.of(-6)
# 2. map
# 2. map
M.map([], fn x -> x * x end) # => []
M.map([1, 2, 3], fn x -> x * x end) # => [1, 4, 9]
# 2. map
defmodule M do
def map(list, fun), do: do_map(list, fun, [])
defp do_map([], _fun, acc), do: Enum.reverse(acc)
defp do_map([head | tail], fun, acc) do
result = fun.(head)
do_map(tail, fun, [result | acc])
end
end
M.map([], fn x -> x * x end) # => []
M.map([1, 2, 3], fn x -> x * x end) # => [1, 4, 9]
# 3. dedup
# 3. dedup
[1, 1, 1, 2, 3, 3]
# 3. dedup
[1, 1, 1, 2, 3, 3] => [{3, 1}, 2, {2, 3}]
# 3. dedup
3
1
1
1
list acc
# 3. dedup
1
1
1 3
list acc
# 3. dedup
1
{2, 1}
3
list acc
# 3. dedup
{3, 1}
3
list acc
# 3. dedup
list acc
3
{3, 1}
reversed
# 3. dedup
defmodule D do
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
defp do_dedup([], acc), do: Enum.reverse(acc)
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
defp do_dedup([], acc), do: Enum.reverse(acc)
defp do_dedup([num, num | tail], acc) do
do_dedup(tail, [{2, num} | acc])
end
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
defp do_dedup([], acc), do: Enum.reverse(acc)
defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do
do_dedup(tail, [{cnt + 1, num} | acc_tail])
end
defp do_dedup([num, num | tail], acc) do
do_dedup(tail, [{2, num} | acc])
end
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
defp do_dedup([], acc), do: Enum.reverse(acc)
defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do
do_dedup(tail, [{cnt + 1, num} | acc_tail])
end
defp do_dedup([num, num | tail], acc) do
do_dedup(tail, [{2, num} | acc])
end
defp do_dedup([head | tail], acc), do: do_dedup(tail, [head | acc])
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 3. dedup
defmodule D do
def dedup(list), do: do_dedup(list, [])
defp do_dedup([], acc), do: Enum.reverse(acc)
defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do
do_dedup(tail, [{cnt + 1, num} | acc_tail])
end
defp do_dedup([num, num | tail], acc) do
do_dedup(tail, [{2, num} | acc])
end
defp do_dedup([head | tail], acc), do: do_dedup(tail, [head | acc])
end
D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4]
D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
# 4. 5 most common words - eager approach
# 4. 5 most common words - eager approach
defmodule Eager do
def answer do
File.read!("moby.txt")
|> String.split("n")
|> Enum.map(%String.trim/1)
|> Enum.filter(&(&1 != ""))
|> Enum.flat_map(&String.split/1)
|> Enum.filter(&(String.length(&1) > 3))
|> Enum.reduce(%{}, fn word, words ->
Map.update(words, word, 1, fn curr -> curr + 1 end)
end)
|> Enum.sort_by(fn {_word, count} -> count end, &>=/2)
|> Enum.take(5)
end
end
Eager.answer()
# => [{"that", 2692}, {"with", 1695}, {"this", 1169}, {"from", 1072}, {"have", 752}]
# 5. 5 most common words - lazy approach
defmodule Lazy do
def answer do
File.stream!("moby.txt")
|> Stream.map(&String.trim/1)
|> Stream.filter(&(&1 != ""))
|> Stream.flat_map(&String.split/1)
|> Stream.filter(&(String.length(&1) > 3))
|> Enum.reduce(%{}, fn word, words ->
Map.update(words, word, 1, fn curr -> curr + 1 end)
end)
|> Enum.sort_by(fn {_word, count} -> count end, &>=/2)
|> Enum.take(5)
end
end
Lazy.answer()
# => [{"that", 2692}, {"with", 1695}, {"this", 1169}, {"from", 1072}, {"have", 752}]
# Let’s talk about `mix`
# Let’s talk about dependencies
# Where to go next?
http://exercism.io/
http://exercism.io/languages/elixir/about
https://adventofcode.com/
https://elixirschool.com/en/
https://github.com/elixirkoans/elixir-koans
https://pragprog.com/book/elixir16/programming-elixir-1-6
https://pragprog.com/book/cdc-elixir/learn-functional-programming-with-elixir
Thank You!
Pre-bootcamp
introduction to Elixir
Paweł Dawczak

Weitere ähnliche Inhalte

Was ist angesagt?

How fast ist it really? Benchmarking in practice
How fast ist it really? Benchmarking in practiceHow fast ist it really? Benchmarking in practice
How fast ist it really? Benchmarking in practiceTobias Pfeiffer
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School ProgrammersSiva Arunachalam
 
Groovy puzzlers jug-moscow-part 2
Groovy puzzlers jug-moscow-part 2Groovy puzzlers jug-moscow-part 2
Groovy puzzlers jug-moscow-part 2Evgeny Borisov
 
Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語ikdysfm
 
Slaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubySlaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubyJason Yeo Jie Shun
 
Python tutorial
Python tutorialPython tutorial
Python tutorialRajiv Risi
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Suyeol Jeon
 
Parse Everything With Elixir
Parse Everything With ElixirParse Everything With Elixir
Parse Everything With ElixirGabriele Lana
 
밑바닥부터 시작하는 의료 AI
밑바닥부터 시작하는 의료 AI밑바닥부터 시작하는 의료 AI
밑바닥부터 시작하는 의료 AINAVER Engineering
 
Frege is a Haskell for the JVM
Frege is a Haskell for the JVMFrege is a Haskell for the JVM
Frege is a Haskell for the JVMjwausle
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in ElixirJesse Anderson
 
The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)GroovyPuzzlers
 

Was ist angesagt? (16)

How fast ist it really? Benchmarking in practice
How fast ist it really? Benchmarking in practiceHow fast ist it really? Benchmarking in practice
How fast ist it really? Benchmarking in practice
 
Python for High School Programmers
Python for High School ProgrammersPython for High School Programmers
Python for High School Programmers
 
Groovy puzzlers jug-moscow-part 2
Groovy puzzlers jug-moscow-part 2Groovy puzzlers jug-moscow-part 2
Groovy puzzlers jug-moscow-part 2
 
Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語Haskellで学ぶ関数型言語
Haskellで学ぶ関数型言語
 
Lập trình Python cơ bản
Lập trình Python cơ bảnLập trình Python cơ bản
Lập trình Python cơ bản
 
Slaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in RubySlaying the Dragon: Implementing a Programming Language in Ruby
Slaying the Dragon: Implementing a Programming Language in Ruby
 
PythonOOP
PythonOOPPythonOOP
PythonOOP
 
Python tutorial
Python tutorialPython tutorial
Python tutorial
 
Elixir
ElixirElixir
Elixir
 
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
Swift - 혼자 공부하면 분명히 안할테니까 같이 공부하기
 
PureScript & Pux
PureScript & PuxPureScript & Pux
PureScript & Pux
 
Parse Everything With Elixir
Parse Everything With ElixirParse Everything With Elixir
Parse Everything With Elixir
 
밑바닥부터 시작하는 의료 AI
밑바닥부터 시작하는 의료 AI밑바닥부터 시작하는 의료 AI
밑바닥부터 시작하는 의료 AI
 
Frege is a Haskell for the JVM
Frege is a Haskell for the JVMFrege is a Haskell for the JVM
Frege is a Haskell for the JVM
 
Intro to OTP in Elixir
Intro to OTP in ElixirIntro to OTP in Elixir
Intro to OTP in Elixir
 
The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)The groovy puzzlers (as Presented at JavaOne 2014)
The groovy puzzlers (as Presented at JavaOne 2014)
 

Ähnlich wie Pre-Bootcamp introduction to Elixir

Τα Πολύ Βασικά για την Python
Τα Πολύ Βασικά για την PythonΤα Πολύ Βασικά για την Python
Τα Πολύ Βασικά για την PythonMoses Boudourides
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionarySoba Arjun
 
Elixir in a nutshell - Fundamental Concepts
Elixir in a nutshell - Fundamental ConceptsElixir in a nutshell - Fundamental Concepts
Elixir in a nutshell - Fundamental ConceptsHéla Ben Khalfallah
 
Beautiful python - PyLadies
Beautiful python - PyLadiesBeautiful python - PyLadies
Beautiful python - PyLadiesAlicia Pérez
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick touraztack
 
Useful javascript
Useful javascriptUseful javascript
Useful javascriptLei Kang
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a bossgsterndale
 
第二讲 Python基礎
第二讲 Python基礎第二讲 Python基礎
第二讲 Python基礎juzihua1102
 
第二讲 预备-Python基礎
第二讲 预备-Python基礎第二讲 预备-Python基礎
第二讲 预备-Python基礎anzhong70
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosEdgar Suarez
 
Php code for online quiz
Php code for online quizPhp code for online quiz
Php code for online quizhnyb1002
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma IntroduçãoÍgor Bonadio
 
Advanced Data Visualization in R- Somes Examples.
Advanced Data Visualization in R- Somes Examples.Advanced Data Visualization in R- Somes Examples.
Advanced Data Visualization in R- Somes Examples.Dr. Volkan OBAN
 
Python quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung FuPython quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung Fuclimatewarrior
 
Puppet Language 4.0 - PuppetConf 2014
Puppet Language 4.0 - PuppetConf 2014Puppet Language 4.0 - PuppetConf 2014
Puppet Language 4.0 - PuppetConf 2014Puppet
 

Ähnlich wie Pre-Bootcamp introduction to Elixir (20)

Τα Πολύ Βασικά για την Python
Τα Πολύ Βασικά για την PythonΤα Πολύ Βασικά για την Python
Τα Πολύ Βασικά για την Python
 
Python Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, DictionaryPython Variable Types, List, Tuple, Dictionary
Python Variable Types, List, Tuple, Dictionary
 
An introduction to Ruby
An introduction to RubyAn introduction to Ruby
An introduction to Ruby
 
Elixir in a nutshell - Fundamental Concepts
Elixir in a nutshell - Fundamental ConceptsElixir in a nutshell - Fundamental Concepts
Elixir in a nutshell - Fundamental Concepts
 
Beautiful python - PyLadies
Beautiful python - PyLadiesBeautiful python - PyLadies
Beautiful python - PyLadies
 
Ruby Language - A quick tour
Ruby Language - A quick tourRuby Language - A quick tour
Ruby Language - A quick tour
 
Useful javascript
Useful javascriptUseful javascript
Useful javascript
 
Refactor like a boss
Refactor like a bossRefactor like a boss
Refactor like a boss
 
Python Tutorial
Python TutorialPython Tutorial
Python Tutorial
 
第二讲 Python基礎
第二讲 Python基礎第二讲 Python基礎
第二讲 Python基礎
 
第二讲 预备-Python基礎
第二讲 预备-Python基礎第二讲 预备-Python基礎
第二讲 预备-Python基礎
 
Desarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutosDesarrollando aplicaciones web en minutos
Desarrollando aplicaciones web en minutos
 
Php code for online quiz
Php code for online quizPhp code for online quiz
Php code for online quiz
 
Elm: give it a try
Elm: give it a tryElm: give it a try
Elm: give it a try
 
Ruby - Uma Introdução
Ruby - Uma IntroduçãoRuby - Uma Introdução
Ruby - Uma Introdução
 
Advanced Data Visualization in R- Somes Examples.
Advanced Data Visualization in R- Somes Examples.Advanced Data Visualization in R- Somes Examples.
Advanced Data Visualization in R- Somes Examples.
 
Begin with Python
Begin with PythonBegin with Python
Begin with Python
 
Python quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung FuPython quickstart for programmers: Python Kung Fu
Python quickstart for programmers: Python Kung Fu
 
Puppet Language 4.0 - PuppetConf 2014
Puppet Language 4.0 - PuppetConf 2014Puppet Language 4.0 - PuppetConf 2014
Puppet Language 4.0 - PuppetConf 2014
 
Python Workshop
Python  Workshop Python  Workshop
Python Workshop
 

Kürzlich hochgeladen

Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...MyIntelliSource, Inc.
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providermohitmore19
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Steffen Staab
 

Kürzlich hochgeladen (20)

Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
Exploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the ProcessExploring iOS App Development: Simplifying the Process
Exploring iOS App Development: Simplifying the Process
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
Try MyIntelliAccount Cloud Accounting Software As A Service Solution Risk Fre...
 
TECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service providerTECUNIQUE: Success Stories: IT Service provider
TECUNIQUE: Success Stories: IT Service provider
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICECHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
CHEAP Call Girls in Pushp Vihar (-DELHI )🔝 9953056974🔝(=)/CALL GIRLS SERVICE
 
Microsoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdfMicrosoft AI Transformation Partner Playbook.pdf
Microsoft AI Transformation Partner Playbook.pdf
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
Shapes for Sharing between Graph Data Spaces - and Epistemic Querying of RDF-...
 

Pre-Bootcamp introduction to Elixir

  • 2. # 1. Introduction - what is Elixir, how to start? # 2. Basic and compound data types # 3. Functions and modules # 4. Let’s talk about `=` # 5. Let’s have some fun! # 6. Let’s talk about `mix` # 7. Let’s talk about dependencies # 8. Suggestions where to find more information # 9. QA
  • 3. # What is Elixir?
  • 4.
  • 5.
  • 6.
  • 7.
  • 9.
  • 10.
  • 11. JVM
  • 12. BEAM
  • 14. Erlang/OTP O - Open T - Telecom P - Platform
  • 15.
  • 17.
  • 19. -module(my_module). -export([hello/1]). hello(Str) -> my_helper(Str). my_helper(Str) -> string:reverse(string:uppercase(Str)). defmodule MyModule do def hello(str) do my_helper(str) end defp my_helper(str) do str |> String.upcase() |> String.reverse() end end
  • 20. # Where do I start?
  • 21.
  • 22. # Install erlang $ asdf plugin-add erlang $ asdf list-all erlang # will list all the available versions $ asdf install erlang 20.3.7 $ asdf global erlang 20.3.7
  • 23. # Install erlang $ asdf plugin-add erlang $ asdf list-all erlang # will list all the available versions $ asdf install erlang 20.3.7 $ asdf global erlang 20.3.7 # Install Elixir $ asdf plugin-add elixir $ asdf list-all elixir $ asdf install elixir 1.6.5 $ asdf global elixir 1.6.5
  • 24. # Install erlang $ asdf plugin-add erlang $ asdf list-all erlang # will list all the available versions $ asdf install erlang 20.3.7 $ asdf global erlang 20.3.7 # Install Elixir $ asdf plugin-add elixir $ asdf list-all elixir $ asdf install elixir 1.6.5 $ asdf global elixir 1.6.5 # [Optional] Install Node
  • 25. # Basic data types
  • 26. nil # => nil true # => true :test # => :test
  • 27. nil # => nil true # => true :test # => :test 1 # => 1 1.2 # => 1.2 "Testing" # => "Testing" 'Testing' # => 'Testing'
  • 28. nil # => nil true # => true :test # => :test 1 # => 1 1.2 # => 1.2 "Testing" # => "Testing" 'Testing' # => 'Testing' is_binary("Testing") # => true is_binary('Testing') # => false is_list("Testing") # => false is_list('Testing') # => true
  • 29. nil # => nil true # => true :test # => :test 1 # => 1 1.2 # => 1.2 "Testing" # => "Testing" 'Testing' # => 'Testing' is_binary("Testing") # => true is_binary('Testing') # => false is_list("Testing") # => false is_list('Testing') # => true pid(0, 13, 0) # => #PID<0.13.0>
  • 30. nil # => nil true # => true :test # => :test 1 # => 1 1.2 # => 1.2 "Testing" # => "Testing" 'Testing' # => 'Testing' is_binary("Testing") # => true is_binary('Testing') # => false is_list("Testing") # => false is_list('Testing') # => true pid(0, 13, 0) # => #PID<0.13.0> make_ref() # => #Reference<0.1816712181.2865233921.217076> # The reference is unique among connected nodes.
  • 32. # Lists [1, 2, 3] # => [1, 2, 3]
  • 33. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"}
  • 34. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel"
  • 35. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5]
  • 36. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3
  • 37. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5]
  • 38. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5] # Structs
  • 39. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5] # Structs defmodule User do end
  • 40. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5] # Structs defmodule User do defstruct [:first_name, :last_name, username: "Guest"] end
  • 41. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5] # Structs defmodule User do defstruct [:first_name, :last_name, username: "Guest"] end %User{first_name: "Pawel", last_name: "Dawczak"}
  • 42. # Lists [1, 2, 3] # => [1, 2, 3] # Tuples {:ok, "Test"} # => {:ok, "Test"} # Maps map = %{first_name: "Pawel", last_name: "Dawczak"} # => %{first_name: "Pawel", last_name: "Dawczak"} map[:first_name] # => "Pawel" # Keyword Lists opts = [per_page: 3, current_page: 1, per_page: 5] # => [per_page: 3, current_page: 1, per_page: 5] opts[:per_page] # => 3 Keyword.get_values(opts, :per_page) # => [3, 5] # Structs defmodule User do defstruct [:first_name, :last_name, username: "Guest"] end %User{first_name: "Pawel", last_name: "Dawczak"} # => User{first_name: "Pawel", last_name: "Dawczak", username: "Guest"}
  • 43. # Functions and modules
  • 44. # Functions inc = fn x -> x + 1 end inc.(3) # => 4
  • 45. # Functions inc = fn x -> x + 1 end inc.(3) # => 4 # Capture operator dec = &(&1 - 1) dec.(3) # => 2
  • 46. # Functions inc = fn x -> x + 1 end inc.(3) # => 4 # Capture operator dec = &(&1 - 1) dec.(3) # => 2 # Modules defmodule MyModule do end
  • 47. # Functions inc = fn x -> x + 1 end inc.(3) # => 4 # Capture operator dec = &(&1 - 1) dec.(3) # => 2 # Modules defmodule MyModule do def square(x) do x * 2 end end MyModule.square(4) # => 8
  • 48. # Functions inc = fn x -> x + 1 end inc.(3) # => 4 # Capture operator dec = &(&1 - 1) dec.(3) # => 2 # Modules defmodule MyModule do def square(x) do x * 2 end def multi(x, y), do: x * y end MyModule.square(4) # => 8 MyModule.multi(3, 4) # => 12
  • 49. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"]
  • 50. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions
  • 51. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"]
  • 52. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"]
  • 53. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"]
  • 54. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6
  • 55. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6 Enum.reduce(1..3, 0, &(&1 + &2)) # => 6
  • 56. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6 Enum.reduce(1..3, 0, &(&1 + &2)) # => 6 Enum.reduce(1..3, 0, &+/2) # => 6
  • 57. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6 Enum.reduce(1..3, 0, &(&1 + &2)) # => 6 Enum.reduce(1..3, 0, &+/2) # => 6 pass = "MySecretPass123"
  • 58. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6 Enum.reduce(1..3, 0, &(&1 + &2)) # => 6 Enum.reduce(1..3, 0, &+/2) # => 6 pass = "MySecretPass123" Enum.map([3, 8, 14], fn x -> String.at(pass, x) end) # => ["e", "P", "3"]
  • 59. # Comprehensions for x <- (1..5), y <- [:blue, :red], rem(x, 2) == 0, do: "#{x * x}-#{y}" # => ["4-blue", "4-red", "16-blue", "16-red"] # Higher-order functions Enum.map([1, 2, 3], fn num -> to_string(num) end) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string(&1)) # => ["1", "2", "3"] Enum.map([1, 2, 3], &to_string/1) # => ["1", "2", "3"] Enum.reduce(1..3, 0, fn num, acc -> num + acc end) # => 6 Enum.reduce(1..3, 0, &(&1 + &2)) # => 6 Enum.reduce(1..3, 0, &+/2) # => 6 pass = "MySecretPass123" Enum.map([3, 8, 14], fn x -> String.at(pass, x) end) # => ["e", "P", "3"] Enum.map([3, 8, 14], &String.at(pass, &1)) # => ["e", "P", "3"]
  • 60. # Let’s talk about `=`
  • 61. x = 1 1 = x 2 = x ** (MatchError) no match of right hand side value: 1 ^x = 1 # ^ - pin operator ^x = 2 list = [20, 21, 22] [a, b, c] = list a # => 20 b # => 21 [a, ^x, c] = list ** (MatchError) no match of right hand side value: [20, 21, 22] hd(list) # => 20 tl(list) # => [21, 22] [head | tail] = list head # => 20 tail # => [21, 22] [a2, 21 | tail] = list a2 # => 20 tail # => [22]
  • 62. map = %{a: "Foo", b: "Bar"}
  • 63. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo"
  • 64. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map
  • 65. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"}
  • 66. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do end
  • 67. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end
  • 68. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end p = %Employee{name: "Pawel", lang: "Elixir"}
  • 69. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end p = %Employee{name: "Pawel", lang: "Elixir"} %{name: name} = p name # => "Pawel"
  • 70. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end p = %Employee{name: "Pawel", lang: "Elixir"} %{name: name} = p name # => "Pawel" %Employee{name: name} = p name # => "Pawel"
  • 71. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end p = %Employee{name: "Pawel", lang: "Elixir"} %{name: name} = p name # => "Pawel" %Employee{name: name} = p name # => "Pawel" lang = "Elixir"
  • 72. map = %{a: "Foo", b: "Bar"} %{a: a} = map a # => "Foo" %{a: "Baz", b: b} = map ** (MatchError) no match of right hand side value: %{a: "Foo", b: "Bar"} defmodule Employee do defstruct [:name, :lang] end p = %Employee{name: "Pawel", lang: "Elixir"} %{name: name} = p name # => "Pawel" %Employee{name: name} = p name # => "Pawel" lang = "Elixir" %Employee{name: name, lang: ^lang} = p name # => "Pawel"
  • 74. File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"}
  • 75. File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"} File.read("./non_existing_one") # => {:error, :enoent}
  • 76. File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"} File.read("./non_existing_one") # => {:error, :enoent} File.read!("./non_existing_one") ** (File.Error) could not read file "./non_existing_one": no such file or directory
  • 77. File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"} File.read("./non_existing_one") # => {:error, :enoent} File.read!("./non_existing_one") ** (File.Error) could not read file "./non_existing_one": no such file or directory HTTPoison.get("https://google.com")
  • 78. File.read("./nice_file") # => {:ok, "Hello World! Nice to see you all!n"} File.read("./non_existing_one") # => {:error, :enoent} File.read!("./non_existing_one") ** (File.Error) could not read file "./non_existing_one": no such file or directory HTTPoison.get("https://google.com") {:ok, %HTTPoison.Response{ body: "...", headers: [ {"Location", "https://www.google.com/"}, {"Content-Type", "text/html; charset=UTF-8"}, {"Cache-Control", "public, max-age=2592000"}, {"Server", "gws"}, {"Content-Length", "220"}, {"X-Frame-Options", "SAMEORIGIN"}, ], request_url: "https://google.com", status_code: 301 }}
  • 80. String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_")))) # Pipe operator String.replace("My Content - 1", ~r/W/, "_") |> format.() |> String.upcase() |> String.reverse()
  • 81. String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_")))) # Pipe operator String.replace("My Content - 1", ~r/W/, "_") |> format.() |> String.upcase() |> String.reverse() # Pipe operator in action
  • 82. String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_")))) # Pipe operator String.replace("My Content - 1", ~r/W/, "_") |> format.() |> String.upcase() |> String.reverse() # Pipe operator in action process = fn {:ok, %{body: body}} -> # parse the body, etc… {:error, error_message} -> Logger.error("Request failed due to: #{error_message}") end
  • 83. String.reverse(String.upcase(format.(String.replace("My Content - 1", ~r/W/, "_")))) # Pipe operator String.replace("My Content - 1", ~r/W/, "_") |> format.() |> String.upcase() |> String.reverse() # Pipe operator in action process = fn {:ok, %{body: body}} -> # parse the body, etc… {:error, error_message} -> Logger.error("Request failed due to: #{error_message}") end "https://google.com" |> HTTPoison.get() |> process.()
  • 84.
  • 85. # Let the fun begin!
  • 87.
  • 88. # 1. Fibonacci! defmodule Fib do def of(0), do: 1 def of(1), do: 1 def of(n) when n > 1, do: of(n-1) + of(n-2) end Fib.of(5) Fib.of(-6)
  • 89.
  • 91. # 2. map M.map([], fn x -> x * x end) # => [] M.map([1, 2, 3], fn x -> x * x end) # => [1, 4, 9]
  • 92. # 2. map defmodule M do def map(list, fun), do: do_map(list, fun, []) defp do_map([], _fun, acc), do: Enum.reverse(acc) defp do_map([head | tail], fun, acc) do result = fun.(head) do_map(tail, fun, [result | acc]) end end M.map([], fn x -> x * x end) # => [] M.map([1, 2, 3], fn x -> x * x end) # => [1, 4, 9]
  • 93.
  • 95. # 3. dedup [1, 1, 1, 2, 3, 3]
  • 96. # 3. dedup [1, 1, 1, 2, 3, 3] => [{3, 1}, 2, {2, 3}]
  • 98. # 3. dedup 1 1 1 3 list acc
  • 99. # 3. dedup 1 {2, 1} 3 list acc
  • 100. # 3. dedup {3, 1} 3 list acc
  • 101. # 3. dedup list acc 3 {3, 1} reversed
  • 102. # 3. dedup defmodule D do end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 103. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 104. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) defp do_dedup([], acc), do: Enum.reverse(acc) end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 105. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) defp do_dedup([], acc), do: Enum.reverse(acc) defp do_dedup([num, num | tail], acc) do do_dedup(tail, [{2, num} | acc]) end end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 106. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) defp do_dedup([], acc), do: Enum.reverse(acc) defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do do_dedup(tail, [{cnt + 1, num} | acc_tail]) end defp do_dedup([num, num | tail], acc) do do_dedup(tail, [{2, num} | acc]) end end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 107. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) defp do_dedup([], acc), do: Enum.reverse(acc) defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do do_dedup(tail, [{cnt + 1, num} | acc_tail]) end defp do_dedup([num, num | tail], acc) do do_dedup(tail, [{2, num} | acc]) end defp do_dedup([head | tail], acc), do: do_dedup(tail, [head | acc]) end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 108. # 3. dedup defmodule D do def dedup(list), do: do_dedup(list, []) defp do_dedup([], acc), do: Enum.reverse(acc) defp do_dedup([num | tail], [{cnt, num} | acc_tail]) do do_dedup(tail, [{cnt + 1, num} | acc_tail]) end defp do_dedup([num, num | tail], acc) do do_dedup(tail, [{2, num} | acc]) end defp do_dedup([head | tail], acc), do: do_dedup(tail, [head | acc]) end D.dedup([1, 2, 3, 4]) # => [1, 2, 3, 4] D.dedup([1, 1, 1, 2, 3, 3]) # => [{3, 1}, 2, {2, 3}]
  • 109.
  • 110. # 4. 5 most common words - eager approach
  • 111. # 4. 5 most common words - eager approach defmodule Eager do def answer do File.read!("moby.txt") |> String.split("n") |> Enum.map(%String.trim/1) |> Enum.filter(&(&1 != "")) |> Enum.flat_map(&String.split/1) |> Enum.filter(&(String.length(&1) > 3)) |> Enum.reduce(%{}, fn word, words -> Map.update(words, word, 1, fn curr -> curr + 1 end) end) |> Enum.sort_by(fn {_word, count} -> count end, &>=/2) |> Enum.take(5) end end Eager.answer() # => [{"that", 2692}, {"with", 1695}, {"this", 1169}, {"from", 1072}, {"have", 752}]
  • 112. # 5. 5 most common words - lazy approach defmodule Lazy do def answer do File.stream!("moby.txt") |> Stream.map(&String.trim/1) |> Stream.filter(&(&1 != "")) |> Stream.flat_map(&String.split/1) |> Stream.filter(&(String.length(&1) > 3)) |> Enum.reduce(%{}, fn word, words -> Map.update(words, word, 1, fn curr -> curr + 1 end) end) |> Enum.sort_by(fn {_word, count} -> count end, &>=/2) |> Enum.take(5) end end Lazy.answer() # => [{"that", 2692}, {"with", 1695}, {"this", 1169}, {"from", 1072}, {"have", 752}]
  • 113. # Let’s talk about `mix`
  • 114.
  • 115.
  • 116.
  • 117.
  • 118.
  • 119.
  • 120.
  • 121.
  • 122.
  • 123.
  • 124.
  • 125.
  • 126.
  • 127.
  • 128.
  • 129.
  • 130.
  • 131.
  • 132.
  • 133.
  • 134.
  • 135.
  • 136.
  • 137.
  • 138.
  • 139.
  • 140.
  • 141.
  • 142.
  • 143.
  • 144.
  • 145.
  • 146.
  • 147.
  • 148.
  • 149.
  • 150. # Let’s talk about dependencies
  • 151.
  • 152.
  • 153.
  • 154.
  • 155.
  • 156.
  • 157.
  • 158.
  • 159.
  • 160.
  • 161.
  • 162.
  • 163.
  • 164.
  • 165.
  • 166.
  • 167. # Where to go next?
  • 175. Thank You! Pre-bootcamp introduction to Elixir Paweł Dawczak