5. Read 4: Lists and Algorithms
Lists
[1, 2, 3]
[1, 2, 3]
List construction
list1 = []
[]
list2 = [3 | list1]
[3]
list3 = [2 | list2]
[2, 3]
list4 = [1 | list3]
[1, 2, 3]
append = fn lst, item -> [item | lst] end
#Function<41.105768164/2 in :erl_eval.expr/6>
[] |> append.(3) |> append.(2) |> append.(1)
[1, 2, 3]
The Enumerable Abstraction
Enum.map([1, 2, 3], fn x -> x * 2 end)
[2, 4, 6]
Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
Enum.sum([1, 2, 3])
6
Enum.map(1..3, fn x -> x * 2 end)
[2, 4, 6]
Pattern Matching and Lists
list = [1, 2, 3]
[1, 2, 3]
[head | tail] = [1, 2, 3]
[1, 2, 3]
head
1
tail
[2, 3]
[] = [1, 2, 3]
[first, second | rest] = list
[1, 2, 3]
second
2
[first, second, third] = list
[1, 2, 3]
Advanced Pattern
list = [1, 2, 3]
[1, 2, 3]
[_, second, third | rest] = list
[1, 2, 3]
second
2
third
3
rest
[]
[1 | [_ | rest]] = list
[1, 2, 3]
rest
[3]
Recursion Over Lists
Simplest Recursive Algorithms
defmodule Calculation do
def total([]), do: 0
def total([head | tail]), do: head + total(tail)
def total_with_accumulator([], partial_total) do
partial_total
end
def total_with_accumulator([first | rest], partial_total) do
total_with_accumulator(rest, partial_total + first)
end
end
{:module, Calculation, <<70, 79, 82, 49, 0, 0, 7, ...>>, {:total_with_accumulator, 2}}
import Calculation
IO.inspect(Calculation.total([1, 2, 3]))
6
6
Tail Recursion With Accumulators
total_with_accumulator([1, 2, 3], 0)
6
Reduce and Anonymous Function
add = fn x, y -> x + y end
#Function<41.105768164/2 in :erl_eval.expr/6>
add.(3, 4)
7
inc = fn x -> add.(x, 1) end
#Function<42.105768164/1 in :erl_eval.expr/6>
inc.(4)
5
4 |> inc.() |> inc.()
6
Higher Order Function
add = fn list_item, acc -> list_item + acc end
#Function<41.105768164/2 in :erl_eval.expr/6>
Enum.reduce(list, 0, add)
# same with
# 0
# |> add.(1)
# |> add.(2)
# |> add.(3)
6
Implement a Polygon
defmodule Point do
def origin, do: {0, 0}
def right({x, y}), do: {x + 1, y}
def left({x, y}), do: {x - 1, y}
def up({x, y}), do: {x, y - 1}
def down({x, y}), do: {x, y + 1}
def mirror({x, y}, w), do: {w - x, y}
def flip({x, y}, h), do: {x, h - y}
def transpose({x, y}), do: {y, x}
def move({x, y}, {cx, cy}), do: {x + cx, y + cy}
def rotate(point, 0, _w, _h) do
point
end
def rotate(point, 90, w, _h) do
point
|> transpose
|> mirror(w)
end
def rotate(point, 180, w, h) do
point
|> flip(h)
|> mirror(w)
end
def rotate(point, 270, _w, h) do
point
|> flip(h)
|> transpose
end
end
{:module, Point, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:rotate, 4}}
import Point
defmodule Polygon do
def rectangle({x, y}, height, width) do
[
{x, y},
{x + width, y},
{x + width, y + height},
{x, y + height}
]
end
def square(point, length) do
rectangle(point, length, length)
end
# def mirror(polygon, w) do
# Enum.map(polygon, fn point -> Point.mirror(point, w) end)
# end
def mirror(polygon, w), do: Enum.map(polygon, &Point.mirror(&1, w))
def flip(polygon, h), do: Enum.map(polygon, &Point.flip(&1, h))
def transpose(polygon), do: Enum.map(polygon, &Point.transpose/1)
def rotate(polygon, degrees, w, h) do
Enum.map(polygon, &Point.rotate(&1, degrees, w, h))
end
def move(polygon, vector) do
Enum.map(polygon, &Point.move(&1, vector))
end
end
{:module, Polygon, <<70, 79, 82, 49, 0, 0, 12, ...>>, {:move, 2}}
r = Polygon.rectangle(Point.origin(), 4, 2)
[{0, 0}, {2, 0}, {2, 4}, {0, 4}]
r |> Polygon.rotate(270, 2, 4)
[{4, 0}, {4, 2}, {0, 2}, {0, 0}]