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 http://www.runningheads.net/wp-content/uploads/2013/05/Curmudgeon_Logo.jpg
So Do Young Ones 4 http://www.clipartbest.com/clipart-MTLL5pbac
����������� We Get 5 http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
���� We Get 6 http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
���� Maintenance Programmer 7 http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
���� I Got 8 http://www.clker.com/cliparts/W/n/3/A/j/2/comfortable-man.svg
The future is functional The future is concurrent 9
Is teaching me a new vocabulary Is changing the way I think 10
T oken Appeal to Authority 11
Ludwig Wittgenstein 12
Ludwig Wittgenstein Logico-Tractatus Philosophicus 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. 13
Ludwig Wittgenstein Logico-Tractatus Philosophicus 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. 14
The limits of my language are the limits of my world Ludwig Wittgenstein— Logico-Tractatus Philosophicus 15
16
How Has Learning Elixir Changed the Way I Think? 17
Functional |> Concurrent |> Pragmatic |> Fun
Functional |> Concurrent |> Pragmatic |> Fun Different
Background • Pattern matching • Functions transform data 20
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
Pattern Match case File.open("myfile") do { :ok, device } -> IO.read(device, :line) { :error, reason } -> IO.puts "FAILED #{reason}" end 22
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
Pattern Matching • Match based on shape and content • Destructure data • Recursive 24
For example… • fib(0) → 0 • fib(1) → 1 • fib(n) → fib(n-1) + fib(n-2) 25
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
defmodule Fib do def fib(0), do: 0 def fib(1), do : 1 def fib(n), do : fib(n-1) + fib(n-2) end • fib(0) → 0 • fib(1) → 1 • fib(n) → fib(n-1) + fib(n-2) 27
Programs Reflect Specification 28
Programs Reflect Specification Implementation Reflects Transformation 29
Length of List • Length of empty list is zero • Length of list with head “h” and tail “t” is 1 + length(t) 30
• 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 ] 31
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
• 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) 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) 33
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
[ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ ] 35
[ 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ] 36
[ {2,2}, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ] 37
[ {2,3}, 3, 4, 4, 5, 6, 6, 6, 6 ] → [ 1 ] 38
[ 3, 4, 4, 5, 6, 6, 6, 6 ] → [ {2, 3}, 1 ] 39
[ 4, 4, 5, 6, 6, 6, 6 ] → [ 3, {2, 3}, 1 ] 40
[ {4,2}, 5, 6, 6, 6, 6 ] → [ 3, {2, 3}, 1 ] 41
[ 5, 6, 6, 6, 6 ] → [ {4,2} , 3, {2,3}, 1 ] 42
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
RLE defmodule Rle do def encode(list), do: _encode(list, []) def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] 44
RLE defmodule Rle do def encode(list), do: _encode(list, []) def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] 45
RLE defmodule Rle do def encode(list), do: _encode(list, []) def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] 46
RLE defmodule Rle do def encode(list), do: _encode(list, []) def _encode([], result), do: Enum.reverse(result) def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] 47
RLE defmodule Rle do def encode(list), do: _encode(list, []) def _encode([], result), do: Enum.reverse(result) def _encode([ a, a | tail ], result) do _encode( [ {a, 2} | tail ], result ) end def _encode( [ {a, n}, a | tail ], result) do _encode( [ {a, n+1} | tail ], result ) end def _encode( [ a | tail ], result) do _encode(tail, [ a | result ]) end end RLE.encode [ 1, 2, 2, 2, 3, 4, 4, 5, 6, 6, 6, 6 ] 48
RLE Input New input Result [] «done» → [ values ] [a,a,…] [ {a,2}, … ] → [ values ] [ {a,n+1}, … ] → [ values ] [{a,n}, a, … ] → [ b, values ] [b, …] [ … ] 49
RLE State New State Result [] «done» → [ values ] [a,a,…] [ {a,2}, … ] → [ values ] [ {a,n+1}, … ] → [ values ] [{a,n}, a, … ] → [ b, values ] [b, …] [ … ] 50
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
Not New • Decision tables (1960s) • State Machines (1960s) • Blackboard systems (1980s) 52
1960s 53
RLE Transformation 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
RLE defmodule Rle do def encode(list) do list |> Enum.reduce([], &_encode/2) Event + State |> 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
RLE defmodule Rle do def encode(list) do Transitions list |> Enum.reduce([], &_encode/2) |> Enum.reverse Event + State 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
Markdown 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. 57
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
Recommend
More recommend