Slide 1

Slide 1 text

Ryan Cromwell Sweet Elixir!

Slide 2

Slide 2 text

Pipeline What’s Elixir? |> Types, Functions, Modules |> Pattern Matching |> Maps, Structs, & Protocols |> Pipelines |> Processes |> OTP, Phoenix

Slide 3

Slide 3 text

Sweet Elixir! What’s Elixir?

Slide 4

Slide 4 text

Functional

Slide 5

Slide 5 text

Erlang VM

Slide 6

Slide 6 text

Concurrent

Slide 7

Slide 7 text

Distributed

Slide 8

Slide 8 text

Sweet Elixir! Setup

Slide 9

Slide 9 text

Mac #Mac! $> brew update! $> brew install erlang! $> brew install elixir! ! #Linux! ! ! #Windows! PS> cinst elixir

Slide 10

Slide 10 text

SWEET ELIXIR! SECTION TITLE

Slide 11

Slide 11 text

$> iex ! iex(1)> IO.puts “hello world!”

Slide 12

Slide 12 text

$> elixir hello_world.exs hello world

Slide 13

Slide 13 text

elixirc hello_world.ex ! $> ls Elixir.HelloWorld.beam

Slide 14

Slide 14 text

$> mix deps.get $> mix compile $> mix phoenix.start

Slide 15

Slide 15 text

hex.pm

Slide 16

Slide 16 text

Sweet Elixir! Types

Slide 17

Slide 17 text

is_number 1 ! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_integer 1! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_number 2.1! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_float 2.1! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_integer 2.1! ! ! ! ! ! ! ! ! ! ! ! #=> false

Slide 18

Slide 18 text

1 == 1.0!! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! 1 === 1.0! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> false

Slide 19

Slide 19 text

is_boolean true! ! ! ! ! ! ! ! ! ! ! #=> true! ! true or false! ! ! ! ! ! ! ! ! ! ! ! #=> true! ! true || false! ! ! ! ! ! ! ! ! ! ! ! #=> true

Slide 20

Slide 20 text

is_atom :selfConf!! ! ! ! ! ! ! ! ! #=> true! ! is_atom true! ! ! ! ! ! ! ! ! ! ! ! ! #=> true

Slide 21

Slide 21 text

is_list [1,2,3]! ! ! ! ! ! ! ! ! ! ! #=> true! ! length [1,2,3]! ! ! ! ! ! ! ! ! ! ! ! #=> 3! ! [1,2] ++ [3,4]! ! ! ! ! ! ! ! ! ! ! ! #=> [1,2,3,4]! ! iex> h Enum! ! iex> h Stream

Slide 22

Slide 22 text

is_tuple {1, “b”, :c}! ! ! ! ! ! ! ! #=> true! ! elem! {1, “b”, :c}, 1!! ! ! ! ! ! ! #=> “b”! ! t = {1, “b”, :c}! set_elem t, 2, :d!! ! ! ! ! ! ! ! ! #=> {1, “b”, :d}! ! Integer.parse “1.0a3”!! ! ! ! ! ! ! #=> {1, “.0a3”}

Slide 23

Slide 23 text

is_list ‘hello’! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_list “hello”! ! ! ! ! ! ! ! ! ! ! #=> true! ! is_binary “hello”!! ! ! ! ! ! ! ! ! #=> true

Slide 24

Slide 24 text

“hello” <> “ world”! ! ! ! ! ! ! ! ! ! #=> “hello world”! ! who = “ryan”! “hello #{who}”! ! ! ! ! ! ! ! ! ! ! ! ! #=> “hello ryan”

Slide 25

Slide 25 text

SWEET ELIXIR! Anonymous Functions

Slide 26

Slide 26 text

add = fn (x, y) -> x + y end! ! add.(2,2)! ! ! ! ! ! ! ! ! ! ! #=> 4

Slide 27

Slide 27 text

do_calc = fn(x,y, calc) -> calc.(x,y) end! ! do_calc.(2,3, add)! ! ! ! ! ! ! ! ! #=> 5! ! do_calc.(2,4, &(&1 * &2))! ! ! ! ! #=> 8

Slide 28

Slide 28 text

SWEET ELIXIR! Modules

Slide 29

Slide 29 text

defmodule Weather do! ! def celsius_to_fahrenheit(celsius) do! ! ! (celsius * 1.8) + 32! ! end! ! ! def boiling, do: 100! ! def freezing, do: 0! end! ! Weather.celsius_to_fahrenheit(20) ! ! #=> 68.0

Slide 30

Slide 30 text

import alias defmodule USWeather do! ! import Weather, only: [freezing: 0,! ! ! ! celsius_to_fahrenheit: 1]! ! ! alias :math, as Math! ! ! def cold_in_michigan do! ! ! celsius_to_fahrenheit(freezing - 10)! ! end! end

Slide 31

Slide 31 text

SWEET ELIXIR! Pattern Matching

Slide 32

Slide 32 text

[head | tail] = [1,2,3,4,5]! ! head! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> 1! ! tail! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> [2,3,4,5]

Slide 33

Slide 33 text

{a,b,c}! = {1,”b”,:c}! ! a!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> 1! ! b!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> “b”! ! c!! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! ! #=> :c

Slide 34

Slide 34 text

{a,b,:other}!= {1,”b”,:c}

Slide 35

Slide 35 text

{a,b,:other}!= {1,”b”,:c}! ! ** (MatchError) no match of right hand side value: {1, "b", :c}

Slide 36

Slide 36 text

Control Flow calculate = fn expression ->! case expression do! {:+, num1, num2} -> num1 + num2! {:-, num1, num2} -> num1 - num2! {:*, num1, 0} -> 0! {:*, num1, num2} -> num1 * num2! end! end

Slide 37

Slide 37 text

defmodule Countdown do! def run(from, to) when from >= to do! run(from, to, from)! end! ! def run(_from, to, current) when to == current do! IO.puts to! IO.puts "Done!"! end! ! def run(from, to, current) do! IO.puts current! run(from, to, current - 1)! end! end Function

Slide 38

Slide 38 text

defmodule PersonPrefixer do! def prefix(p = %{ gender: :male }), do: "Mr."! def prefix(p = %{ gender: :female }), do: "Mrs."! def prefix(p), do: ""! end! ! PersonPrefixer.prefix %{first: “Sandy”, gender: :female} #=> “Mrs”

Slide 39

Slide 39 text

SWEET ELIXIR! Maps Structs Protocols

Slide 40

Slide 40 text

Maps speaker = %{! first: “Ryan”,! last: “Cromwell”,! twitter: “@cromwellryan”,! “home town” => “Dayton, OH”! }! ! speaker[:twitter] #=> “@cromwellryan”! ! speaker[“Home Town”] #=> “Dayton, OH”

Slide 41

Slide 41 text

Structs defmodule Kid do! ! defstruct name: "ryan", age: 7! end

Slide 42

Slide 42 text

Protocols defprotocol Good do! @doc "Returns true if data is considered good"! def good?(data)! end

Slide 43

Slide 43 text

Ad-hoc Polymorphism defimpl Good, for: Kid do! ! def good?(%Kid{name: "Ryan"}), do: true! ! def good?(_), do: false! end! ! Good.good? %Kid{name: "Ryan"}! ! ! ! ! ! ! ! #> true! Good.good? %Kid{name: "Ben"}!! ! ! ! ! ! ! ! #> false

Slide 44

Slide 44 text

SWEET ELIXIR! Pipelines

Slide 45

Slide 45 text

Enum.map [1,2,3,4], fn (x) -> x * 2 !! ! ! ! ! #=> [2,4,6,8]! ! [1,2,3,4] |> Enum.map(fn (x) -> x *2)! ! ! ! ! #=> [2,4,6,8]

Slide 46

Slide 46 text

lines = String.split file_content, "\n"! lines = Stream.filter lines, &(String.length(&1) > 0)! lengths = Stream.map lines, &(String.split &1)! triangles = Stream.map lengths, &(list_to_tuple &1)! classifications = Stream.map triangles, &( %{sides: &1, classification: Classifier.classify &1} )! ! messages = Stream.map classifications, &( "Triangle #{inspect &1[:sides]} is #{&1[:classification]}" )! result = Enum.join(messages, "\n")! ! IO.puts result before

Slide 47

Slide 47 text

file_content! |> String.split("\n")! |> Stream.filter( &(String.length(&1) > 0) )! |> Stream.map( &(String.split &1) )! |> Stream.map( &(list_to_tuple &1) )! |> Stream.map( &(%{sides: &1, class: Classifier.classify &1}) )! |> Stream.map( &("Triangle #{inspect &1[:sides]} is #{&1[:class]}") )! |> Enum.join("\n")! |> IO.puts! after

Slide 48

Slide 48 text

SWEET ELIXIR! Processes

Slide 49

Slide 49 text

Process Process Process

Slide 50

Slide 50 text

pid = spawn fn ->! receive do! {sender, :ping} ->! IO.puts "Got ping"! send sender, :pong! end! end

Slide 51

Slide 51 text

Live Coding

Slide 52

Slide 52 text

SWEET ELIXIR! OTP

Slide 53

Slide 53 text

‣ Supervisor ‣ GenServer ‣ GenFSM ‣ GenEvent ‣ Application

Slide 54

Slide 54 text

No content

Slide 55

Slide 55 text

SWEET ELIXIR! phoenix

Slide 56

Slide 56 text

github.com/phoenixframework/phoenix

Slide 57

Slide 57 text

$> mix phoenix.new your_app /path/to/scaffold/your_app! ! $> mix do deps.get, compile! ! $> mix phoenix.start

Slide 58

Slide 58 text

Inspired by Rails defmodule ChatDemoEx.Router do! use Phoenix.Router! use Phoenix.Router.Socket, mount: "/ws"! ! plug Plug.Static, at: "/static", from: :chat_demo_ex! get "/", ChatDemoEx.Controllers.Pages, :index, as: :page! ! channel "rooms", Chat.Channels.Rooms! end

Slide 59

Slide 59 text

defmodule Chat.Channels.Rooms do! use Phoenix.Channel! ! def event(socket, "new:message", message) do! broadcast socket, "new:message", message! ! socket! end! end Elixir

Slide 60

Slide 60 text

Javascript chan.send("new:message", {! ! username: “cromwellryan”, ! ! body: “hello internets!”! });! !

Slide 61

Slide 61 text

SWEET ELIXIR! LEARN YOU SOME ELIXIR

Slide 62

Slide 62 text

Resources ‣ elixir-lang.org ‣ elixirsips.com ‣ elixirconf.com (July 25-26) ! ‣ PragProg: Programming Elixir ! ‣ github.com/cromwellryan/sweetelixir ‣ http://bit.ly/sweetelixir-short

Slide 63

Slide 63 text

THANKS! @cromwellryan [email protected]