Skip to content

Latest commit

 

History

History
261 lines (203 loc) · 4.15 KB

File metadata and controls

261 lines (203 loc) · 4.15 KB

Elixir Koans - 21 Control Flow

import ExUnit.Assertions

Intro

Control Flow - Making decisions and choosing paths

If statements evaluate conditions

result = if true, do: "yes", else: "no"
assert result == ___

If can be written in block form

result =
  if 1 + 1 == 2 do
    "math works"
  else
    "math is broken"
  end
assert result == ___

Unless is the opposite of if

result = unless false, do: "will execute", else: "will not execute"
assert result == ___

Nil and false are falsy, everything else is truthy

assert if(nil, do: "truthy", else: "falsy") == ___
assert if(false, do: "truthy", else: "falsy") == ___
assert if(0, do: "truthy", else: "falsy") == ___
assert if("", do: "truthy", else: "falsy") == ___
assert if([], do: "truthy", else: "falsy") == ___

Case matches against patterns

result =
  case {1, 2, 3} do
    {4, 5, 6} -> "no match"
    {1, x, 3} -> "matched with x = #{x}"
  end
assert result == ___

Case can have multiple clauses with different patterns

check_number = fn x ->
  case x do
    0 -> "zero"
    n when n > 0 -> "positive"
    n when n < 0 -> "negative"
  end
end
assert check_number.(5) == ___
assert check_number.(0) == ___
assert check_number.(-3) == ___

Case clauses are tried in order until one matches

check_list = fn list ->
  case list do
    [] -> "empty"
    [_] -> "one element"
    [_, _] -> "two elements"
    _ -> "many elements"
  end
end
assert check_list.([]) == ___
assert check_list.([:a]) == ___
assert check_list.([:a, :b]) == ___
assert check_list.([:a, :b, :c, :d]) == ___

Cond evaluates conditions until one is truthy

temperature = 25

weather =
  cond do
    temperature < 0 -> "freezing"
    temperature < 10 -> "cold"
    temperature < 25 -> "cool"
    temperature < 30 -> "warm"
    true -> "hot"
  end
assert weather == ___

Cond requires at least one clause to be true

safe_divide = fn x, y ->
  cond do
    y == 0 -> {:error, "division by zero"}
    true -> {:ok, x / y}
  end
end
assert safe_divide.(10, 2) == ___
assert safe_divide.(10, 0) == ___

Case can destructure complex patterns

parse_response = fn response ->
  case response do
    {:ok, %{status: 200, body: body}} -> "Success: #{body}"
    {:ok, %{status: status}} when status >= 400 -> "Client error: #{status}"
    {:ok, %{status: status}} when status >= 500 -> "Server error: #{status}"
    {:error, reason} -> "Request failed: #{reason}"
  end
end
assert parse_response.({:ok, %{status: 200, body: "Hello"}}) == ___
assert parse_response.({:ok, %{status: 404}}) == ___
assert parse_response.({:error, :timeout}) == ___

Guards in case can use complex expressions

categorize = fn number ->
  case number do
    n when is_integer(n) and n > 0 and rem(n, 2) == 0 -> "positive even integer"
    n when is_integer(n) and n > 0 and rem(n, 2) == 1 -> "positive odd integer"
    n when is_integer(n) and n < 0 -> "negative integer"
    n when is_float(n) -> "float"
    _ -> "other"
  end
end
assert categorize.(4) == ___
assert categorize.(3) == ___
assert categorize.(-5) == ___
assert categorize.(3.14) == ___
assert categorize.("hello") == ___

Multiple conditions can be checked in sequence

process_user = fn user ->
  if user.active do
    if user.verified do
      if user.premium do
        "premium verified active user"
      else
        "verified active user"
      end
    else
      "unverified active user"
    end
  else
    "inactive user"
  end
end

user = %{active: true, verified: true, premium: false}
assert process_user.(user) == ___

Next Steps