Slide 1

Slide 1 text

Thinking Functionally Carlos Souza - @caike Code School / Pluralsight with Elixir

Slide 2

Slide 2 text

Functional Programming

Slide 3

Slide 3 text

Elixir

Slide 4

Slide 4 text

Elixir = Erlang VM (BEAM)

Slide 5

Slide 5 text

Elixir = Erlang VM (BEAM) movie: "Erlang - The Movie" Erlang: The Movie

Slide 6

Slide 6 text

No content

Slide 7

Slide 7 text

My Life The CompSci Years

Slide 8

Slide 8 text

The Comp Sci Years #1
 Learn to 
 Learn New Things

Slide 9

Slide 9 text

The Comp Sci Years PROLOG
 Describe the problem and not the solution

Slide 10

Slide 10 text

A Taste of Prolog (@the_thagomizer)

Slide 11

Slide 11 text

Paradigms

Slide 12

Slide 12 text

Paradigms #1
 Learn to 
 Learn New Things

Slide 13

Slide 13 text

Paradigms #2 
 Forget What
 You Know

Slide 14

Slide 14 text

Paradigms

Slide 15

Slide 15 text

Paradigms conf = "ATO"

Slide 16

Slide 16 text

Functional Programming

Slide 17

Slide 17 text

Functional Programming - Pure Functions - Pattern Matching - Recursion

Slide 18

Slide 18 text

Functional Programming - Pure Functions - Pattern Matching - Recursion

Slide 19

Slide 19 text

Pure Functions - Pure Functions - Pattern Matching - Recursion

Slide 20

Slide 20 text

Two Rules of Pure Functions #1 - Return value should rely 
 entirely on arguments #2 - No side effects

Slide 21

Slide 21 text

Pure Functions

Slide 22

Slide 22 text

Pure Functions

Slide 23

Slide 23 text

Pure Functions How many in the basket ?

Slide 24

Slide 24 text

Pure Functions

Slide 25

Slide 25 text

Pure Functions I place in an empty
 basket and eat . 
 
 How many are left ?

Slide 26

Slide 26 text

Pure Functions

Slide 27

Slide 27 text

#1 - Return value should rely 
 entirely on arguments #2 - No side effects Two Rules of Pure Functions

Slide 28

Slide 28 text

Pure Functions Pure Functions defmodule Account do def balance(initial, spending) do initial - spending end end

Slide 29

Slide 29 text

Pure Functions Pure Functions defmodule Account do def balance(initial, spending) do initial - spending end end IO.puts 800 Account.balance(1000, 200)

Slide 30

Slide 30 text

Pure Functions vs. Objects account.currentBalance() vs. Account.balance(1000, 200)

Slide 31

Slide 31 text

Pure Functions Invoke function f on data x Invoke function g on the return value of function f on data x, and on data y f(x) g(f(x), y) j(i(h(g(f(x),y),z))) Now this is getting silly...

Slide 32

Slide 32 text

It’s Hard to Read “From the Inside Out” defmodule Account do def balance(initial, spending) do interest(discount(initial, 10), 0.1) end def discount(total, amount) do ... end def interest(total, rate) do ... end end

Slide 33

Slide 33 text

Piping Functions - |> defmodule Account do def balance(initial, spending) do discount(initial, 10) |> interest(0.1) end ... end defmodule Account do def balance(initial, spending) do discount(initial, 10) |> interest(0.1) |> format("$") end ... end read from left to righ new functions added to the end

Slide 34

Slide 34 text

Piping Functions the Elixir style - |> defmodule Account do def balance(initial, spending) do initial |> discount(10) |> interest(0.1) |> format("$") ... end end

Slide 35

Slide 35 text

Reading contents from a CSV file defmodule Budget do def list_transactions do File.read("transactions.csv") |> parse_file |> filter |> normalize |> sort |> print end ... end https://github.com/codeschool/budget-elixir

Slide 36

Slide 36 text

Pattern Matching - Pure Functions - Pattern Matching - Recursion

Slide 37

Slide 37 text

Pattern Matching Primitives conf = "ATO"

Slide 38

Slide 38 text

BrookeSam Brooke, Sam Elements from the list on the right... ...are a perfect match against those from the list on the left. users = ["Brooke", "Sam"] IO.puts users [first, second] = users IO.puts "#{first}, #{second}" Pattern Matching Lists - [ ]

Slide 39

Slide 39 text

Splitting Lists with [head|tail ] [head|tail] = ["Brooke", "Sam", "Niki"] "Brooke" ["Sam", "Nikki"]

Slide 40

Slide 40 text

Pattern Matching Tuples - { } {:ok, content} {:ok, "some content"} {:error, :enoent} Reading a file File.read("transactions.csv") =

Slide 41

Slide 41 text

File.read("transactions.csv") Reading Return Tuples {:error, error} file exists file doesn't exist {:ok, content}

Slide 42

Slide 42 text

Pattern Matching in Functions defmodule Budget do def list_transactions do |> parse_file end ... end or takes ONE argument {:ok, content} {:error, error} File.read("transactions.csv")

Slide 43

Slide 43 text

Pattern Matching in Functions No IF statement! defmodule Budget do ... 
 def parse_file({:ok, content}) do
 ... end 
 def parse_file({:error, error}) do ... end end

Slide 44

Slide 44 text

Pattern Matching Maps - %{ } empty variables are populated person = %{ "name" => "Brooke", "age" => 42 } = person , "age" => age matches keys on the right %{ "name" => name }

Slide 45

Slide 45 text

Pattern Matching Portions of Maps - %{ } person = %{ "name" => "Brooke", "age" => 42 } only reads portion of the map %{ "name" => name } = person

Slide 46

Slide 46 text

Pattern Matching Nested Maps - %{ } person = %{ "name" => "Brooke", "address" => %{ "city" => "Orlando", "state" => "FL"}} %{ "address" => %{ "state" => state }} = person matching on portion of the nested keys

Slide 47

Slide 47 text

Pattern Matching in Phoenix defmodule FireStarterWeb.VideoController do ... def show( ) do video = Repo.get(Video, id) render conn, "show.html", video: video end end Phoenix is MVC Elixir for the web. pattern matching! conn, %{"id" => id}

Slide 48

Slide 48 text

Pattern Matching in the wild pattern matching! https://github.com/mschae/cors_plug

Slide 49

Slide 49 text

Pattern Matching Everywhere

Slide 50

Slide 50 text

Recursion - Pure Functions - Pattern Matching - Recursion

Slide 51

Slide 51 text

Recursion "Recently refreshed sourdough, bubbling
 through fermentation: the recipe calls for 
 some sourdough left over from the last 
 time the same recipe was made." From https://en.wikipedia.org/wiki/Recursion:

Slide 52

Slide 52 text

Two Cases for Recursion All recursive functions involve the following two cases (or two clauses): 1. The base case or terminating scenario, 
 where the function does NOT invoke itself. 2. The recursive case, where computation 
 happens and the function invokes itself.

Slide 53

Slide 53 text

Recursive Factorial defmodule MyMath do def factorial(1) do 1 end def factorial(n) do n * factorial(n - 1) end end MyMath.factorial(3) #=> 6 MyMath.factorial(4) #=> 24 terminating
 scenario recursive case

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

No content

Slide 56

Slide 56 text

Recursion [%{"name" => "Cyle Larin", "position" => "forward"}, %{"name" => "Antonio Nocerino", "position" => "midfielder"}, %{"name" => "Joe Bendik", "position" => "goalkeeper"}, %{"name" => "Jason Kreis", "position" => "coach"}] %{"name" => "Joe Bendik", "position" => "goalkeeper"} Listing players from Orlando City Soccer

Slide 57

Slide 57 text

Recursion defmodule SoccerTeam do def list_all() do end def get_goalie() do end end SoccerTeam.list_all SoccerTeam.get_goalie

Slide 58

Slide 58 text

Recursion defmodule SoccerTeam do def list_all() do end end SoccerTeam.list_all

Slide 59

Slide 59 text

Recursion defmodule SoccerTeam do use HTTPoison.Base def list_all() do url = "https://..." get_url(url) |> parse end defp parse( ) do end end %{status_code: 200, body: json_response} {:ok, list } = Poison.Parser.parse(json_response) list

Slide 60

Slide 60 text

Recursion [%{"name" => "Cyle Larin", "position" => "forward"}, %{"name" => "Antonio Nocerino", "position" => "midfielder"}, %{"name" => "Joe Bendik", "position" => "goalkeeper"}, %{"name" => "Jason Kreis", "position" => "coach"}] A list of maps

Slide 61

Slide 61 text

Recursion %{"name" => "Joe Bendik", "position" => "goalkeeper"} Finding the goalkeeper

Slide 62

Slide 62 text

Recursion defmodule SoccerTeam do def get_goalie() do end end SoccerTeam.get_goalie

Slide 63

Slide 63 text

Recursion defmodule SoccerTeam do use HTTPoison.Base def get_goalie() do url = "https://..." get_url(url) |> parse end end |> find_goalie

Slide 64

Slide 64 text

Recursion defmodule SoccerTeam do ... def find_goalie([%{"position" => "goalkeeper"} = head|_]) do head end def find_goalie([_|tail]) do find_goalie(tail) end def find_goalie([]) do raise "Error. No goalie found" end end No for loop No while statement

Slide 65

Slide 65 text

Recursive Factorial defmodule MyMath do def factorial(1) do 1 end def factorial(n) do n * factorial(n - 1) end end MyMath.factorial(10_000_000)

Slide 66

Slide 66 text

Recursion with no TCO

Slide 67

Slide 67 text

Recursive Factorial defmodule MyMath do def factorial(1) do 1 end def factorial(n) do n * factorial(n - 1) end end MyMath.factorial(10_000_000) not the LAST expression in this function

Slide 68

Slide 68 text

Recursive Factorial defmodule MyMath do def factorial(1) do 1 end def factorial(n) do n * factorial(n - 1) end end MyMath.factorial(10_000_000) the LAST expression in this function

Slide 69

Slide 69 text

Tail Call Optimization MyMath.factorial(10_000_000) defmodule MyMath do def factorial(1, acc) do acc end def factorial(n, acc) do factorial(n-1, n * acc) end def factorial(n) do factorial(n, 1) end end

Slide 70

Slide 70 text

Tail Call Optimization

Slide 71

Slide 71 text

That was a lot! - Functional Programming - Elixir - Pure Functions, Pattern Matching and 
 Recursion - Recursion with TCO FTW

Slide 72

Slide 72 text

Resources codeschool.com pragprog.com

Slide 73

Slide 73 text

Thinking Functionally with Elixir Thank you! # Carlos Souza - @caike Code School / Pluralsight