150 lines
3.3 KiB
Elixir
150 lines
3.3 KiB
Elixir
defmodule PatternMatching do
|
|
use Koans
|
|
|
|
@intro "PatternMatching"
|
|
|
|
koan "One matches one" do
|
|
assert match?(1, ___)
|
|
end
|
|
|
|
koan "Patterns can be used to pull things apart" do
|
|
[head | tail] = [1, 2, 3, 4]
|
|
|
|
assert head == ___
|
|
assert tail == ___
|
|
end
|
|
|
|
koan "And then put them back together" do
|
|
head = 1
|
|
tail = [2, 3, 4]
|
|
|
|
assert ___ == [head | tail]
|
|
end
|
|
|
|
koan "Some values can be ignored" do
|
|
[_first, _second, third, _fourth] = [1, 2, 3, 4]
|
|
|
|
assert third == ___
|
|
end
|
|
|
|
koan "Strings come apart just as easily" do
|
|
"Shopping list: " <> items = "Shopping list: eggs, milk"
|
|
|
|
assert items == ___
|
|
end
|
|
|
|
koan "Maps support partial pattern matching" do
|
|
%{make: make} = %{type: "car", year: 2016, make: "Honda", color: "black"}
|
|
|
|
assert make == ___
|
|
end
|
|
|
|
koan "Lists must match exactly" do
|
|
assert_raise ___, fn ->
|
|
[a, b] = [1,2,3]
|
|
end
|
|
end
|
|
|
|
koan "So does the keyword lists" do
|
|
kw_list = [type: "car", year: 2016, make: "Honda"]
|
|
[_type | [_year | [tuple]]] = kw_list
|
|
assert tuple == {___, ___}
|
|
end
|
|
|
|
koan "The pattern can make assertions about what it expects" do
|
|
assert match?([1, _second, _third], ___)
|
|
end
|
|
|
|
def make_noise(%{type: "cat"}), do: "Meow"
|
|
def make_noise(%{type: "dog"}), do: "Woof"
|
|
def make_noise(_anything), do: "Eh?"
|
|
|
|
koan "Functions perform pattern matching on their arguments" do
|
|
cat = %{type: "cat"}
|
|
dog = %{type: "dog"}
|
|
snake = %{type: "snake"}
|
|
|
|
assert make_noise(cat) == ___
|
|
assert make_noise(dog) == ___
|
|
assert make_noise(snake) == ___
|
|
end
|
|
|
|
koan "And they will only run the code that matches the argument" do
|
|
name = fn
|
|
("duck") -> "Donald"
|
|
("mouse") -> "Mickey"
|
|
(_other) -> "I need a name!"
|
|
end
|
|
|
|
assert name.("mouse") == ___
|
|
assert name.("duck") == ___
|
|
assert name.("donkey") == ___
|
|
end
|
|
|
|
koan "Errors are shaped differently than successful results" do
|
|
dog = %{type: "dog"}
|
|
|
|
result = case Map.fetch(dog, :type) do
|
|
{:ok, value} -> value
|
|
:error -> "not present"
|
|
end
|
|
|
|
assert result == ___
|
|
end
|
|
|
|
defmodule Animal do
|
|
defstruct [:kind, :name]
|
|
end
|
|
|
|
koan "You can pattern match into the fields of a struct" do
|
|
%Animal{name: name} = %Animal{kind: "dog", name: "Max"}
|
|
assert name == ___
|
|
end
|
|
|
|
koan "Structs will even match with a regular map" do
|
|
%{name: name} = %Animal{kind: "dog", name: "Max"}
|
|
assert name == ___
|
|
end
|
|
|
|
koan "A value can be bound to a variable" do
|
|
a = 1
|
|
assert a == ___
|
|
end
|
|
|
|
koan "A variable can be rebound" do
|
|
a = 1
|
|
a = 2
|
|
assert a == ___
|
|
end
|
|
|
|
koan "A variable can be pinned to use its value when matching instead of binding to a new value" do
|
|
pinned_variable = 1
|
|
|
|
example = fn
|
|
(^pinned_variable) -> "The number One"
|
|
(2) -> "The number Two"
|
|
(number) -> "The number #{number}"
|
|
end
|
|
assert example.(1) == ___
|
|
assert example.(2) == ___
|
|
assert example.(3) == ___
|
|
end
|
|
|
|
koan "Pinning works anywhere one would match, including 'case'" do
|
|
pinned_variable = 1
|
|
result = case 1 do
|
|
^pinned_variable -> "same"
|
|
other -> "different #{other}"
|
|
end
|
|
|
|
assert result == ___
|
|
end
|
|
|
|
koan "Trying to rebind a pinned variable will result in an error" do
|
|
a = 1
|
|
assert_raise MatchError, fn() ->
|
|
^a = ___
|
|
end
|
|
end
|
|
end
|