On Github jfeaver / talk-try-elixir
defmodule FizzBuzz do def fizz_word(0, 0, _), do: "FizzBuzz" def fizz_word(0, _, _), do: "Fizz" def fizz_word(_, 0, _), do: "Buzz" def fizz_word(_, _, n), do: n def fizzbuzz(n) do fizz_word( rem(n,3), rem(n,5), n ) end def result(n) do Enum.map(1..n, fn(n) -> fizzbuzz(n) end) end def print(n) do result(n) |> Enum.join(", ") |> IO.puts end end FizzBuzz.print(100)Pattern Matching | Pipe Operator Functional Bits: pattern matching, pipe operator, recursion features
Erlang was originally developed in 1986 by Ericsson for telephony applications to support highly concurrent systems
Elixir doesn't have built-in random or time libraries (although there are multiple packages). Let's use Erlang's libraries:
defmodule Random do def uniform do :random.uniform end def seed do :random.seed(:erlang.now) end end
defmacro match?(left, right) do quote do case unquote(right) do unquote(left) -> true _ -> false end end end
iex> list = [{:a,1},{:b,2},{:a,3}] [a: 1, b: 2, a: 3] iex> Enum.filter list, fn (thing) -> match?({:a, _}, thing) end [a: 1, a: 3]Taken from: Elixir: It's Not About Syntax Built from the beginning with a focus on metaprogramming using macros
defmodule Math do def sum_list([head|tail], accumulator) do sum_list(tail, head + accumulator) end def sum_list([], accumulator) do accumulator end end Math.sum_list([1, 2, 3], 0) #=> 6Taken from: Elixir Getting Started: Recursion
# Compile the module and create a process that evaluates `area_loop` in the shell pid = spawn(fn -> Geometry.area_loop() end) #=> #PID<0.40.0> # Send a message to `pid` that will match a pattern in the receive statement send pid, {:rectangle, 2, 3} #=> Area = 6 # {:rectangle,2,3} send pid, {:circle, 2} #=> Area = 12.56000000000000049738 # {:circle,2} # The shell is also a process, you can use `self` to get the current pid self() #=> #PID<0.27.0>Taken from: Learn X in Y Minutes - Elixir # Elixir relies on the actor model for concurrency. All we need to write # concurrent programs in elixir are three primitives: spawning processes, # sending messages and receiving messages.
iex> a = [ 1,2,3 ] iex> b = [[ 1,2,3 ]] iex> [c] = [[ 1,2,3 ]] iex> a == c true iex> [ x,y,z ] = [ 1,2,3 ] iex> z 3 iex> "Today is " <> date = "Today is December 16th" iex> date "December 16th"
defmodule MyApp do def callback(:ok, data) do # success end def callback(:error, data) do # handle failure end endBack To FizzBuzz pervasive You're not assigning 1 to a, you're challenging elixir to find a way to make that true
The pipe operator(|>) is most helpful when transforming data through a sequence. The operator pipes the result of an expression into the first argument of the next function. Confusing, nested function calls no longer need temporary variables to make them readable:
# Confusing, nested function calls def print(n) do IO.puts( Enum.join( result(n), ", " ) ) end # versus using the pipe operator def print(n) do result(n) |> Enum.join(", ") |> IO.puts endBack To FizzBuzz
it 'releases one invite credit when it is withdrawn' do sender = @invite.sender expect{ @invite.withdraw; sender.reload }. to change{ sender.available_invite_credits.length }. by(1) end
it 'releases one invite credit when it is withdrawn' do sender = @invite.sender expect{ @invite.withdraw }. to change{ User.available_invite_credits(sender.id).length }. by(1) end
# find the author counts author_counts = [] author_counts_index = -1 current_author = '' for i in 0...commits.length commit = commits[i] if commit.author == current_author author_counts[author_counts_index][1] += 1 else current_author = commit.author author_counts << [commit.author, 1] author_counts_index += 1 end end
commits.sort_by do |commit| commit.author end. chunk do |commit| commit.author end. each do |author, author_commits| puts "#{author} has #{author_commits.count} commits" end
My approaches to some Ruby problems have probably changed in subtle ways. Learning Elixir has been fun and will help me learn other languages (and their strengths) faster. I'm probably also better prepared to use Proc objects, the Proc#curry method, and Enumerator::Lazy objects but directly practicing them would be even better (perhaps with katas).