Rigor Mortis (avoiding) 1 Dave is an Old Fart - - PDF document

rigor mortis
SMART_READER_LITE
LIVE PREVIEW

Rigor Mortis (avoiding) 1 Dave is an Old Fart - - PDF document

Dave Thomas @/+pragdave Rigor Mortis (avoiding) 1 Dave is an Old Fart http://24.media.tumblr.com/tumblr_lr7ypweBfM1qa9b8ro1_500.png Old Farts Get Stuck in Their Ways


slide-1
SLIDE 1

1

Dave Thomas
 @/+pragdave

(avoiding)

Rigor Mortis

slide-2
SLIDE 2

Dave is an Old Fart

http://24.media.tumblr.com/tumblr_lr7ypweBfM1qa9b8ro1_500.png
slide-3
SLIDE 3

Old Farts Get Stuck in Their Ways

http://www.runningheads.net/wp-content/uploads/2013/05/Curmudgeon_Logo.jpg
slide-4
SLIDE 4 http://www.clipartbest.com/clipart-MTLL5pbac

4

So Do Young Ones

slide-5
SLIDE 5

We Get

5

http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
slide-6
SLIDE 6

We Get

6

http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
slide-7
SLIDE 7

7

http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
  • Maintenance

Programmer

slide-8
SLIDE 8

8

I Got

http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
slide-9
SLIDE 9

The future is functional The future is concurrent

9

slide-10
SLIDE 10

Is teaching me a new vocabulary Is changing the way I think

10

slide-11
SLIDE 11

T

  • ken Appeal to Authority

11

slide-12
SLIDE 12

Ludwig Wittgenstein

12

slide-13
SLIDE 13

Ludwig Wittgenstein

13

How far my efforts agree with those of other philosophers I will not decide. Indeed what I have here written makes no claim to novelty in points of detail; and therefore I give no sources, because it is indifferent to me whether what I have thought has already 
 been thought before me by another.

Logico-Tractatus Philosophicus

slide-14
SLIDE 14

Ludwig Wittgenstein
 Logico-Tractatus Philosophicus

14

How far my efforts agree with those of other philosophers I will not decide. Indeed what I have here written makes no claim to novelty in points of detail; and therefore I give no sources, because it is indifferent to me whether what I have thought has already 
 been thought before me by another.

slide-15
SLIDE 15

The limits of my 
 language are the 
 limits of my world

Ludwig Wittgenstein—Logico-Tractatus Philosophicus 15

slide-16
SLIDE 16

16

slide-17
SLIDE 17

How Has Learning Elixir Changed the Way I Think?

17

slide-18
SLIDE 18

Functional |> Concurrent |> Pragmatic |> Fun

slide-19
SLIDE 19

Functional |> Concurrent |> Pragmatic |> Fun

Different

slide-20
SLIDE 20

Background

  • Pattern matching
  • Functions transform data

20

slide-21
SLIDE 21

Pattern Match

a = 1 { c, d } = { 2, 3 } [ e, f, g ] = [ 4, 5, 6 ] "Elixir " <> rest = "Elixir Rocks!" # rest => "Rocks!" [ head | tail ] = [ 1, 2, 3, 4, 5, 6 ] # head => 1 # tail => [ 2,3,4,5,6 ]

21

slide-22
SLIDE 22

Pattern Match

case File.open("myfile") do { :ok, device } -> IO.read(device, :line) { :error, reason } -> IO.puts "FAILED #{reason}" end

22

slide-23
SLIDE 23

Pattern Match

my_fun = fn :plus, a, b -> a + b :times, a, b -> a * b end IO.puts my_fun.(:plus, 3, 4) # => 7 IO.puts my_fun.(:times, 3, 4) # => 12 def other_fun(:minus, a, b), do: a - b def other_fun(:divide, a, b), do: a/b

23

slide-24
SLIDE 24

Pattern Matching

  • Match based on shape and content
  • Destructure data
  • Recursive

24

slide-25
SLIDE 25

For example…

  • fib(0) → 0
  • fib(1) → 1
  • fib(n) → fib(n-1) + fib(n-2)

25

slide-26
SLIDE 26

Fibonacci

defmodule Fib do def fib(0), do: 0 def fib(1), do: 1 def fib(n), do: fib(n-1) + fib(n-2) end IO.puts Fib.fib(10)

26

slide-27
SLIDE 27
  • fib(0) → 0
  • fib(1) → 1
  • fib(n) → fib(n-1) + fib(n-2)

27

defmodule Fib do def fib(0), do: 0 def fib(1), do: 1 def fib(n), do: fib(n-1) + fib(n-2) end

slide-28
SLIDE 28

Programs Reflect Specification

28

slide-29
SLIDE 29

Programs Reflect Specification

29

Implementation Reflects Transformation

slide-30
SLIDE 30

Length of List

  • Length of empty list is zero
  • Length of list with head “h” and 


tail “t” is 1 + length(t)

30

slide-31
SLIDE 31

31

  • Length of empty list is zero
  • Length of list with head “h” and 


tail “t” is 1 + length(t)

defmodule MyList do def len([]), do: 0 def len([ _head | tail ]), do: 1 + len(tail) end IO.puts MyList.len [ 5, 4, 3 ]

slide-32
SLIDE 32

Map

  • Map of an empty list is an empty list
  • Map of list with head “h” and tail “t” 


is a list whose head is func(h) and whose tail is map(t)

32

slide-33
SLIDE 33

33

defmodule MyList do def map([], _func), do: [] def map([ h | t ], func), do: [ func.(h) | map(t, func) ] end MyList.map [ 1,2,3,4,5], &(&1*&1)

  • Map of an empty list is an empty list
  • Map of list with head “h” and tail “t” 


is a list whose head is func(h) and whose tail is map(t)

slide-34
SLIDE 34

More Practical

  • Run-length encode a list of values:



 Runs of two or more of the same value “v” are replaced with { v, count }

[ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1, {2, 3}, 3, {4, 2}, 5, {6, 4} ]

34

slide-35
SLIDE 35

[ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ ]

35

slide-36
SLIDE 36

[ 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ]

36

slide-37
SLIDE 37

[ {2,2}, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ]

37

slide-38
SLIDE 38

[ {2,3}, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ]

38

slide-39
SLIDE 39

[ 3, 4, 4, 5, 6, 6, 6, 6 ] → [ {2, 3}, 1 ]

39

slide-40
SLIDE 40

[ 4, 4, 5, 6, 6, 6, 6 ] → [ 3, {2, 3}, 1 ]

40

slide-41
SLIDE 41

[ {4,2}, 5, 6, 6, 6, 6 ] → [ 3, {2, 3}, 1 ]

41

slide-42
SLIDE 42

[ 5, 6, 6, 6, 6 ] → [ {4,2} , 3, {2,3}, 1 ]

42

slide-43
SLIDE 43

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

43

slide-44
SLIDE 44

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

44

def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end

slide-45
SLIDE 45

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

45

def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end

slide-46
SLIDE 46

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

46

def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end

slide-47
SLIDE 47

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

47

def _encode([], result), do: Enum.reverse(result) def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end

slide-48
SLIDE 48

RLE

defmodule Rle do def encode(list), do: _encode(list, []) end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ]

48

def _encode([], result), do: Enum.reverse(result) def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end

slide-49
SLIDE 49

Input New input Result [] «done» → [ values ] [a,a,…] [ {a,2}, … ] → [ values ] [{a,n}, a, … ] [ {a,n+1}, … ] → [ values ]

[b, …] [ … ]

→ [ b, values ]

RLE

49

slide-50
SLIDE 50

State New State

Result [] «done» → [ values ] [a,a,…] [ {a,2}, … ] → [ values ] [{a,n}, a, … ] [ {a,n+1}, … ] → [ values ]

[b, …] [ … ]

→ [ b, values ]

RLE

50

slide-51
SLIDE 51

RLE

defmodule Rle do def encode(list) do list |> Enum.reduce([], &_encode/2) |> Enum.reverse end def _encode(next, result) do case {next, result} do {a, [ a | rest ] } -> [ {a,2} | rest ] {a, [ {a,n} | rest ] } -> [ {a, n+1} | rest ] {a, rest } -> [ a | rest ] end end end

51

slide-52
SLIDE 52

Not New

  • Decision tables (1960s)
  • State Machines (1960s)
  • Blackboard systems (1980s)

52

slide-53
SLIDE 53

53

1960s

slide-54
SLIDE 54

RLE

defmodule Rle do def encode(list) do list |> Enum.reduce([], &_encode/2) |> Enum.reverse end def _encode(next, result) do case {next, result} do {a, [ a | rest ] } -> [ {a,2} | rest ] {a, [ {a,n} | rest ] } -> [ {a, n+1} | rest ] {a, rest } -> [ a | rest ] end end end

54

Transformation

slide-55
SLIDE 55

RLE

defmodule Rle do def encode(list) do list |> Enum.reduce([], &_encode/2) |> Enum.reverse end def _encode(next, result) do case {next, result} do {a, [ a | rest ] } -> [ {a,2} | rest ] {a, [ {a,n} | rest ] } -> [ {a, n+1} | rest ] {a, rest } -> [ a | rest ] end end end

55

Event + State

slide-56
SLIDE 56

RLE

defmodule Rle do def encode(list) do list |> Enum.reduce([], &_encode/2) |> Enum.reverse end def _encode(next, result) do case {next, result} do {a, [ a | rest ] } -> [ {a,2} | rest ] {a, [ {a,n} | rest ] } -> [ {a, n+1} | rest ] {a, rest } -> [ a | rest ] end end end

56

Transitions

Event + State

slide-57
SLIDE 57

Markdown

57

System Types ============ These types reflect resources in the underlying Erlang VM. IDs and Ports

  • A PID is a reference to a local or remote process, and a port is a

reference to a resource (typically external to the application) that you'll be reading or writing.

slide-58
SLIDE 58

Markdown

defp parse([ %Line.Blank{}, %Line.Text{content: heading}, %Line.SetextUnderlineHeading{level: level} | rest ], result) do parse(rest, [ %Heading{content: heading, level: level} | result ]) end

58

slide-59
SLIDE 59

Large Scale, Too

  • REST Service Request:

get_special_offers_for_user

  • identify user from auth token
  • find local offers
  • find national offers
  • merge and respond

59

} asynchronous

slide-60
SLIDE 60

Find local offers Find national offers Lookup User Format response

Request: auth token Response: . . .

60

slide-61
SLIDE 61

%{ get_offers: auth }

  • > %{ get_offers: auth, user: user_from(auth) }

%{ get_offers: auth, user: nil }

  • > %{ respond: :not_authorized }

%{ get_offers: auth, user: user }

  • > async_get_local_offers(user)

async_get_national_offers(user) %{ get_offers: auth, user_user, national: :error },

  • > respond_with_error

%{ get_offers: auth, user_user, local: :error },

  • > respond_with_error

%{ get_offers: auth, user_user, national: national, local: local },

  • > format_response(user, national, local)

61

slide-62
SLIDE 62

Enough Already

62

slide-63
SLIDE 63

The Point

  • Pattern matches are the rules in a state machine
  • Each match specifies a transformation of state
  • The transformation is the application of functions

63

slide-64
SLIDE 64

Interesting Opportunities

  • Easily made parallel
  • DSL could define business flow
  • granular reuse
  • easier testing
  • better error handling

64

slide-65
SLIDE 65

Think Differently

65

slide-66
SLIDE 66

Program Differently

66

slide-67
SLIDE 67

Program Differently

  • New languages are an opportunity
  • Let’s not recreate where we came from
  • Let’s have fun

67

slide-68
SLIDE 68

68

My name is Inigo

  • Montoya. You

killed my programming paradigm. Prepare to learn.

Dave Thomas
 Pragmatic Programmers
 @/+pragdave