2015-07-08
Luke Imhoff
luke_imhoff@rapid7.com | Kronic.Deth@gmail.com | |
@limhoff-r7 | @KronicDeth | |
@KronicDeth |
defmodule Math do
def sum(a, b) do
a + b
end
def square(x) do
x * x
end
end
Math.sum(1, 2) # 3
Math.square 3 # 9
defmodule Geometry do
def area({:rectangle, w, h}) do
w * h
end
def area({:circle, r}) when is_number(r) do
3.14 * r * r
end
end
Geometry.area({:rectangle, 2, 3}) #=> 6
Geometry.area({:circle, 3}) #=> 28.25999999999999801048
defmodule Recursion do
def sum_list([head | tail], acc) do
sum_list(tail, acc + head)
end
def sum_list([], acc) do
acc
end
end
Recursion.sum_list([1,2,3], 0) #=> 6
iex> pid = spawn_link fn ->
...> receive do
...> {:ping, client} -> send client, :pong
...> end
...> end
#PID<9014.59.0>
iex> send pid, {:ping, self}
{:ping, #PID<0.73.0>}
iex> flush
:pong
:ok
mix test
doctest
defmodule Atom do
@moduledoc """
Convenience functions for working with atoms.
See also `Kernel.is_atom/1`.
"""
@doc """
Converts an atom to a string.
Inlined by the compiler.
## Examples
iex> Atom.to_string(:foo)
"foo"
"""
@spec to_string(atom) :: String.t
def to_string(atom) do
:erlang.atom_to_binary(atom, :utf8)
end
end
Erlang | Elixir | |
---|---|---|
Run when? | Preprocess | Compile |
Code generation | String substitution | AST manipulation |
Language Features | Functions with Arguments | Full |
defmodule ElixirLunchAndLearnTest do
use ExUnit.Case
test "the truth" do
assert 1 + 1 != 2
end
end
defmodule MimeTypes do
HTTPotion.start
HTTPotion.Response[body: body] = HTTPotion.get(
"http://svn.apache.org/repos/asf/httpd/httpd/trunk/docs/conf/mime.types"
)
Enum.each String.split(body, %r/\n/), fn (line) ->
unless line == "" or line =~ %r/^#/ do
[ mimetype | _exts ] = String.split(line)
def is_valid?(unquote(mimetype)), do: true
end
end
def is_valid?(_mimetype), do: false
end
MimeTypes.is_valid?("application/vnd.exn") #=> false
MimeTypes.is_valid?("application/json") #=> true
defprotocol Blank do
@doc "Returns true if data is considered blank/empty"
def blank?(data)
end
# Integers are never blank
defimpl Blank, for: Integer do
def blank?(_), do: false
end
# Just empty list is blank
defimpl Blank, for: List do
def blank?([]), do: true
def blank?(_), do: false
end
defprotocol Phoenix.Param do
def to_param(term)
end
defmodule User do
@derive {Phoenix.Param, key: :email}
defstruct [:id, :email]
end
user = %User{id: 1, username: "alice@example.com"}
Phoenix.Param.to_param(user) # "alice@example.com"
# deeply nested function calls
def main(argv) do
output(process(parse_args(argv)))
end
# single-use variables
def main(argv) do
parsed_args = parse_args(argv)
processed = process(parsed_args)
output(processed)
end
# Pipes
def main(argv) do
argv
|> parse_args
|> process
|> output
end
defmodule FizzBuzz do
def fizz_buzz(n), do: fizz_buzz(rem(n, 3), rem(n, 5), n)
defp fizz_buzz(0, 0, _), do: "FizzBuzz"
defp fizz_buzz(0, _, _), do: "Fizz"
defp fizz_buzz(_, 0, _), do: "Buzz"
defp fizz_buzz(_, _, n), do: n
end
FizzBuzz.fizz_buzz 10 # "Buzz"
FizzBuzz.fizz_buzz 11 # 11
FizzBuzz.fizz_buzz 12 # "Fizz"
FizzBuzz.fizz_buzz 13 # 13
FizzBuzz.fizz_buzz 14 # 14
FizzBuzz.fizz_buzz 15 # "FizzBuzz"
f = fn -> receive do
after
:infinity -> :ok
end
end
{_, bytes} = Process.info(spawn(f), :memory)
bytes # 2680
defmodule ElixirLunchAndLearn.Chain do
def run(n) do
{microseconds, result} = :timer.tc(__MODULE__, :create_processes, [n])
IO.puts "#{result} (Calculated in #{microseconds} microseconds)"
end
end
defmodule ElixirLunchAndLearn.Chain do
def create_processes(n) do
last = Enum.reduce 1..n,
self,
fn(_, send_to) ->
spawn(__MODULE__, :counter, [send_to])
end
# start the count by sending
send last, 0
# and wait for the result to come back to us
receive do
final_answer when is_integer(final_answer) ->
"Result is #{inspect final_answer}"
end
end
end
defmodule ElixirLunchAndLearn.Chain do
def counter(next_pid) do
receive do
n ->
send next_pid, n + 1
end
end
end
> elixir --erl "+P 1000000" -r lib/elixir_lunch_and_learn/chain.ex -e "ElixirLunchAndLearn.Chain.run(1_000_000)"
Result is 1000000 (Calculated in 11658944 microseconds)