Added one more example with guards, fixed typos and identation.

This commit is contained in:
mrshankly 2013-07-03 00:03:44 +01:00
parent 231a211ef2
commit a136cfe86a

View File

@ -141,33 +141,33 @@ number < atom < reference < functions < port < pid < tuple < list < bit string
# `if` expression
if false do
"This will never be seen"
"This will never be seen"
else
"This will"
"This will"
end
# There's also `unless`
unless true do
"This will never be seen"
"This will never be seen"
else
"This will"
"This will"
end
# Remember pattern matching? Many control-flow structures in elixir rely on it.
# `case` allows us to compare a value against many patterns:
case {:one, :two} do
{:four, :five} ->
"This won't match"
{:one, x} ->
"This will match and assign `x` to `:two`"
_ ->
"This will match any value"
{:four, :five} ->
"This won't match"
{:one, x} ->
"This will match and assign `x` to `:two`"
_ ->
"This will match any value"
end
# It's common practive to assign a value to `_` if we don't need it.
# For example, if only the head of a list matters to us:
[head | _] = [1,2,3]
[head | _] = [1,2,3]
head #=> 1
# For better readability we can do the following:
@ -177,35 +177,35 @@ head #=> :a
# `cond` lets us check for many conditions at the same time.
# Use `cond` instead of nesting many `if` expressions.
cond do
1 + 1 == 3 ->
"I will never be seen"
2 * 5 == 12 ->
"Me neither"
1 + 2 == 3 ->
"But I will"
1 + 1 == 3 ->
"I will never be seen"
2 * 5 == 12 ->
"Me neither"
1 + 2 == 3 ->
"But I will"
end
# It is common to see a last condition equal to `true`, which will always match.
cond do
1 + 1 == 3 ->
"I will never be seen"
2 * 5 == 12 ->
"Me neither"
true ->
"But I will (this is essentially an else)"
1 + 1 == 3 ->
"I will never be seen"
2 * 5 == 12 ->
"Me neither"
true ->
"But I will (this is essentially an else)"
end
# `try/catch` is used to catch values that are thrown, it also supports an
# `after` clause that is invoked whether or not a value is catched.
try do
throw(:hello)
throw(:hello)
catch
message -> "Got #{message}."
message -> "Got #{message}."
after
IO.puts("I'm the after clause.")
IO.puts("I'm the after clause.")
end
#=> I'm the after clause
# "Got :hello"
# "Got :hello"
## ---------------------------
## -- Modules and Functions
@ -218,8 +218,8 @@ square.(5) #=> 25
# They also accept many clauses and guards. Guards let you fine tune pattern matching,
# they are indicated by the `when` keyword:
f = fn
x, y when x > 0 -> x + y
x, y -> x * y
x, y when x > 0 -> x + y
x, y -> x * y
end
f.(1, 3) #=> 4
@ -234,32 +234,32 @@ elem({1,2,3}, 0) #=> 1
# You can group several functions into a module. Inside a module use `def`
# to define your functions.
defmodule Math do
def sum(a, b) do
a + b
end
def sum(a, b) do
a + b
end
def square(x) do
x * x
end
def square(x) do
x * x
end
end
Math.sum(1, 2) #=> 3
Match.square(3) #=> 9
# To compile our little Math module save it as `math.ex` and use `elixirc`
elixirc math.ex
# To compile our simple Math module save it as `math.ex` and use `elixirc`
# in your terminal: elixirc math.ex
# Inside a module we can define functions with `def` and private functions with `defp`.
# A function defined with `def` is available to be invoked from other modules,
# a private function can only be invoked locally.
defmodule PrivateMath do
def sum(a, b) do
do_sum(a, b)
end
def sum(a, b) do
do_sum(a, b)
end
defp do_sum(a, b) do
a + b
end
defp do_sum(a, b) do
a + b
end
end
PrivateMath.sum(1, 2) #=> 3
@ -267,27 +267,29 @@ PrivateMath.do_sum(1, 2) #=> ** (UndefinedFunctionError)
# Function declarations also support guards and multiple clauses:
defmodule Geometry do
def area({:rectangle, w, h}) do
w * h
end
def area({:rectangle, w, h}) do
w * h
end
def area({:circle, r}) when is_number(r) do
3.14 * r * r
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
Geometry.area({:circle, "not_a_number"})
#=> ** (FunctionClauseError) no function clause matching in Geometry.area/1
# Due to immutability, recursion is a big part of elixir
defmodule Recursion do
def sum_list([head | tail], acc) do
sum_list(tail, acc + head)
end
def sum_list([head | tail], acc) do
sum_list(tail, acc + head)
end
def sum_list([], acc) do
acc
end
def sum_list([], acc) do
acc
end
end
Recursion.sum_list([1,2,3], 0) #=> 6
@ -295,12 +297,12 @@ Recursion.sum_list([1,2,3], 0) #=> 6
# Elixir modules support attributes, there are built-in attributes and you
# may also add custom attributes.
defmodule MyMod do
@moduledoc """
This is a built-in attribute on a example module.
"""
@moduledoc """
This is a built-in attribute on a example module.
"""
@my_data 100 # This is a custom attribute.
IO.inspect(@my_data) #=> 100
@my_data 100 # This is a custom attribute.
IO.inspect(@my_data) #=> 100
end
## ---------------------------
@ -322,18 +324,18 @@ joe_info = joe_info.age(31) #=> Person[name: "Joe", age: 31, height: 180]
# The `try` block with the `rescue` keyword is used to handle exceptions
try do
raise "some error"
raise "some error"
rescue
RuntimeError -> "rescued a runtime error"
_error -> "this will rescue any error"
RuntimeError -> "rescued a runtime error"
_error -> "this will rescue any error"
end
# All exceptions have a message
try do
raise "some error"
raise "some error"
rescue
x in [RuntimeError] ->
x.message
x in [RuntimeError] ->
x.message
end
## ---------------------------
@ -354,16 +356,16 @@ spawn(f) #=> #PID<0.40.0>
# For all of this to be useful we need to be able to receive messages. This is
# achived with the `receive` mechanism:
defmodule Geometry do
def area_loop do
receive do
{:rectangle, w, h} ->
IO.puts("Area = #{w * h}")
area_loop()
{:circle, r} ->
IO.puts("Area = #{3.14 * r * r}")
area_loop()
end
end
def area_loop do
receive do
{:rectangle, w, h} ->
IO.puts("Area = #{w * h}")
area_loop()
{:circle, r} ->
IO.puts("Area = #{3.14 * r * r}")
area_loop()
end
end
end
# Compile the module and create a process that evaluates `area_loop` in the shell