ALL ARTICLES
Day 1: The Tyranny of the Rocket Equation
I did the Advent of Code 2019 day 1 challenge in Erlang!
#!/usr/bin/env escript
-mode(native).
%% https://adventofcode.com/2019/day/1
main(Args) ->
Nums = lists:append(read_list("~d")),
Sol =
case Args of
["2"] -> fuel_proper(Nums);
_ -> fuel_mod(Nums)
end,
io:format("~w~n", [Sol]).
read_list(Pat) ->
read_list(Pat, []).
read_list(Pat, Acc) ->
case io:fread("", Pat) of
{ok, Res} -> read_list(Pat, [Res|Acc]);
eof -> lists:reverse(Acc)
end.
fuel_mod(Nums) ->
lists:sum([(Mod div 3) - 2 || Mod <- Nums]).
fuel_proper(Nums) ->
lists:sum([mod_proper(Mod) || Mod <- Nums]).
mod_proper(Mod) ->
mod_proper(Mod, 0).
mod_proper(Lift, Fuel) ->
NF = (Lift div 3) - 2,
case NF < 0 of
true -> Fuel;
false -> mod_proper(NF, Fuel + NF)
end.
READ MORE
Do you know the answer to this Elixir Challenge?
- **Discussion**
# What will this return ?
MapSet.new(1..32) |> Enum.to_list()
# Observe what happens if we request 33 elements instead:
MapSet.new(1..33) |> Enum.to_list()
# Let's discuss what happens here;
# What is special about the number 33 and what does it mean ?
- **Explanation**
A bunch of stuff is happening here. Elixir has a concept of protocols which provide polymorphism on data types and structures. In our example we pipe the result of generating a MapSet
into the to_list/1
function on the Enum
module. Enum
is a module containing functions that work on data types implementing the Enumerable protocol; examples of these are lists, maps, and ranges. Enum
can do all kinds of neat stuff on these, such as taking a slice of a range:
# Give me first 5 elements after the 10th element in the range 1 to 20
iex> Enum.slice(1..20, 10, 5)
[11, 12, 13, 14, 15]
Intuitively we would think a data structure has an order; for instance a Range
is a sequence of numbers increasing (or decreasing) from the start point to the end point of the range. When we ask to turn a Range
into a list using Enum.to_list/1
it will materialize into a list of numbers, going from first to last. A Range has a natural order, and so does a list—which is implemented as a linked list; the elements has an order based on the order they were inserted, as the element at the head of the list will point to the next in the list.
But this intuition fails when it comes to the Map
data structure. If we ask for the list representation of a Map
containing keys consisting of integers we might get fooled into believing that a Map
has an reliable order:
iex> Enum.to_list(%{1 => :a, 2 => :b, 3 => :c})
[{1, :a}, {2, :b}, {3, :c}]
Which might seem odd when we try to construct a Map
with 33 or more elements and observe what happens when we convert it to a list:
iex> Enum.into(1..33, %{}, fn (x) -> {x, x} end) |> Enum.to_list()
[{11, 11}, {26, 26}, {15, 15} | _output_omitted]
What is special about 33? Why did we get a seemingly random order in our return?
The technical explanation is that the Erlang Virtual Machine stores maps in different data structures depending on the number of elements in the Map
. For a Map
containing 32 or less elements it is stored in a sorted array—which explains why we observe an order iterating over the elements using the Enum
and Stream
functions—and when the Map
contain more than 32 elements the Erlang VM will switch to a data structure called «hash array mapped trie,» which provides fast lookups for bigger data sets as well as very fast insertions. When we convert the big map to a list we will get whatever order the internal representation has; which is not intuitive.
For our initial example we convert a MapSet
to a list. The MapSet
data structure is useful for when we want to store terms in a set. It allows us to ask if a term is present, and perform comparisons between two sets, such as getting the difference or intersection, in a fast and efficient manner. Behind the scenes a MapSet
uses a Map
to store its values, so it inherit the performance from the Map
, but also the unordered nature when the set grows above 32 elements.
To conclude:
# A Map is an unordered data structure, and we should never rely on the order of a Map
While we seemingly observe an order when we convert maps to lists, or iterate over them, we should never rely on the order of a Map
. Assuming a reliable order could break our application in a future Erlang/OTP release, as the OTP team could choose to change the internal representation of maps. That said, it is fine to use the functions in the Enum
module to iterate over a map, as long as no assumptions on the order of the elements are made.
- https://en.wikipedia.org/wiki/Hash_array_mapped_trie
- https://elixir-lang.org/getting-started/protocols.html
- https://hexdocs.pm/elixir/Enumerable.html#content
- https://hexdocs.pm/elixir/Map.html#content
- https://hexdocs.pm/elixir/MapSet.html#content
Did you find this interesting? Want more? Join like-minded individuals at Code Elixir LDN 2019, July 18 in London, UK. Also, for more reading, check out our previous blog post in this series.
READ MOREDay 14: Chocolate Charts - Advent of Code 2018
I did the Advent of Code 2018 day 14 challenge in Erlang! Parts one and two are as follows:
#!/usr/bin/env escript
-mode(native).
%% https://adventofcode.com/2018/day/14
-define(INPUT, 635041).
main(Args) ->
Sol =
case Args of
["2"] -> seek([6,3,5,0,4,1]);
_ ->
{_, P} = score(?INPUT),
P
end,
io:format("~p~n", [Sol]).
seek(Target) ->
seek(Target, 1000).
seek(Target, Range) ->
io:format("~p~n", [Range]),
{M, _} = score(Range),
io:format("Score done~n"),
case find(Target, M) of
{true, I} -> I;
false -> seek(Target, Range * 10)
end.
find(Target, M) ->
Rs = [D || {_, D} <- lists:sort(maps:to_list(M))],
io:format("Seq Done"),
find(0, Rs, Target).
find(_, [], _) ->
false;
find(I, [_|RRs] = Rs, Ds) ->
case lists:prefix(Ds, Rs) of
true ->
{true, I};
false ->
find(I + 1, RRs, Ds)
end.
score(N) ->
score(0, 1, #{0 => 3, 1 => 7}, 2, N).
score(_, _, Map, M, N) when M > N + 11 ->
Fold =
fun(X, A) ->
A * 10 + maps:get(X, Map)
end,
{Map, lists:foldl(Fold, 0, lists:seq(N, N + 9))};
score(E1, E2, Map, M, N) ->
%io:format("~p~n", [[D || {_, D} <- lists:sort(maps:to_list(Map))]]),
S1 = maps:get(E1, Map),
S2 = maps:get(E2, Map),
New = S1 + S2,
%io:format("~p~n", [{E1, E2, S1, S2, New}]),
{NewMap, NewM} =
case New > 9 of
true ->
{Map#{M => New div 10, M + 1 => New rem 10}, M + 2};
false ->
{Map#{M => New}, M + 1}
end,
{NewE1, NewE2} =
{(E1 + S1 + 1) rem NewM, (E2 + S2 + 1) rem NewM},
score(NewE1, NewE2, NewMap, NewM, N).
READ MORE
Day 12: Subterranean Sustainability - Advent of Code 2018
I did the Advent of Code 2018 day 12 challenge in Erlang! Parts one and two are as follows:
#!/usr/bin/env escript
-mode(native).
%% https://adventofcode.com/2018/day/12
main(Args) ->
{ok, [Initial]} = io:fread("", "initial state: ~s"),
{ok, []} = io:fread("", ""),
Evolve = make_evolve(read_list("~c~c~c~c~c => ~c")),
Sol =
case Args of
["2"] -> sum_state(state_after(50 * 1000, {0, Initial}, Evolve));
_ -> sum_state(state_after(20, {0, Initial}, Evolve))
end,
io:format("~p~n", [Sol]).
read_list(Pat) ->
read_list(Pat, []).
read_list(Pat, Acc) ->
case io:fread("", Pat) of
{ok, Res} -> read_list(Pat, [Res|Acc]);
eof -> lists:reverse(Acc)
end.
make_evolve(List) ->
Fold =
fun([[A],[B],[C],[D],[E],[F]], Map) ->
Map#{[A,B,C,D,E] => F}
end,
lists:foldl(Fold, #{}, List).
state_after(0, State, _Evolve) ->
State;
state_after(N, State, Evolve) ->
%io:format("~p~n", [State]),
NewState = evolve(State, Evolve),
state_after(N - 1, NewState, Evolve).
evolve({F, Line}, Evolve) ->
evolve("...." ++ Line ++ "....", Evolve, F-2, []).
evolve([A,B,C,D,E|Rest], Evolve, F, Acc) ->
NC = maps:get([A,B,C,D,E], Evolve, $.),
{NF, NAcc} =
case Acc =:= [] andalso NC =:= $. of
true -> {F + 1, []};
false -> {F, [NC|Acc]}
end,
evolve([B,C,D,E|Rest], Evolve, NF, NAcc);
evolve(_, _, F, Acc) ->
Pred = fun(C) -> C =:= $. end,
{F, lists:reverse(lists:dropwhile(Pred, Acc))}.
sum_state({F, List}) ->
sum_state(F, List, 0).
sum_state(_, [], Sum) -> Sum;
sum_state(I, [C|Rest], Sum) ->
NSum =
case C =:= $# of
true -> Sum + I;
false -> Sum
end,
sum_state(I+1, Rest, NSum).
READ MORE
Day 9: Marble Mania - Advent of Code 2018
I did the Advent of Code 2018 day 9 challenge in Erlang! Parts one and two are as follows:
#!/usr/bin/env escript
-mode(native).
%% https://adventofcode.com/2018/day/9
main(Args) ->
{ok, [N, M]} = io:fread("", "~d ~d"),
Sol =
case Args of
["2"] -> high_score(N, M * 100);
_ -> high_score(N, M)
end,
io:format("~p~n", [Sol]).
high_score(N, M) ->
high_score({[0], []}, 1, #{}, N, M).
high_score(_Marbles, Turn, Scores, _N, Last) when Turn > Last ->
FindWinner =
fun(K, V, {_, MaxV} = Max) ->
case V > MaxV of
true -> {K, V};
false -> Max
end
end,
{_Winner, HighScore} = maps:fold(FindWinner, {0, 0}, Scores),
HighScore;
high_score(Marbles, Turn, Scores, N, Last) ->
case Turn rem 23 =:= 0 of
false ->
NewMarbles = add_rotate_2(Turn, Marbles),
high_score(NewMarbles, Turn + 1, Scores, N, Last);
true ->
{H, NewMarbles} = rem_rotate_neg7(Marbles),
Points = Turn + H,
Update = fun(V) -> V + Points end,
Winner = Turn rem N,
NewScores = maps:update_with(Winner, Update, Points, Scores),
high_score(NewMarbles, Turn + 1, NewScores, N, Last)
end.
add_rotate_2(New, {[0], []}) -> {[New, 0], []};
add_rotate_2(New, {Front, Back}) ->
case Front of
[H1, H2|T] ->
{[New|T], [H2, H1|Back]};
[H1] ->
[H2|T] = lists:reverse(Back),
{[New|T], [H2, H1]};
[] ->
[H1, H2|T] = lists:reverse(Back),
{[New|T], [H2, H1]}
end.
rem_rotate_neg7({Front, Back}) ->
case Back of
[HN1, HN2, HN3, HN4, HN5, HN6, HN7|R] ->
{HN7, {[HN6, HN5, HN4, HN3, HN2, HN1|Front], R}};
_ ->
Rev = Back ++ lists:reverse(Front),
rem_rotate_neg7({[], Rev})
end.
READ MORE
Day 8: Memory maneuver - Advent of Code
I did the Advent of Code 2018 day 8 challenge in Erlang! Parts one and two are as follows:
#!/usr/bin/env escript
-mode(native).
%% https://adventofcode.com/2018/day/8
main(Args) ->
[Input] = read_input(),
Sol =
case Args of
["2"] -> value([Input], [1]);
_ -> sum_metadata([Input])
end,
io:format("~p~n", [Sol]).
read_input() ->
read_input(1).
read_input(0) -> [];
read_input(Nodes) ->
{ok, [ChildrenCount, MetaCount]} = io:fread("", "~d ~d"),
Children = read_input(ChildrenCount),
ReadMeta =
fun() ->
{ok, [M]} = io:fread("", "~d"),
M
end,
Meta = [ReadMeta() || _ <- lists:seq(1, MetaCount)],
Rest = read_input(Nodes - 1),
[{Children, Meta} | Rest].
sum_metadata([]) -> 0;
sum_metadata([{Children, Meta}|Rest]) ->
A = sum_metadata(Rest),
B = sum_metadata(Children),
C = lists:sum(Meta),
A + B + C.
value([], Meta) ->
lists:sum(Meta);
value(Children, Which) ->
Marked = select(Which, Children),
lists:sum([value(C, M) || {C, M} <- Marked]).
select(Which, Children) ->
select(Which, Children, []).
select([], _, Acc) ->
Acc;
select([N|R], Children, Acc) ->
try
C = lists:nth(N, Children),
select(R, Children, [C|Acc])
catch
_:_ ->
select(R, Children, Acc)
end.
READ MORE
Day 7: The Sum of Its Parts - Advent of Code 2018
I did the Advent of Code 2018 day 7 challenge in Elixir! Parts one and two are as follows:
defmodule Day7 do
@instruction_info ~r/Step (\w+) must be finished before step (\w+) can begin/
def part1(input) do
input
|> read_input()
|> parse_input()
|> discover_dependencies([])
end
defp read_input(input) do
input
|> File.read!()
|> String.split("\n", trim: true)
end
defp parse_input(lines) do
Enum.reduce(lines, %{}, fn line, acc ->
[step, dependency] = Regex.run(@instruction_info, line, capture: :all_but_first)
acc
|> Map.put_new(step, [])
|> Map.update(dependency, [step], fn dependencies ->
Enum.sort([step | dependencies])
end)
end)
|> Enum.to_list()
end
defp discover_dependencies(deps_tree, acc) when map_size(deps_tree) == 0do
acc |> Enum.reverse() |> Enum.join()
end
defp discover_dependencies(deps_tree, acc) do
{step, []} = Enum.find(deps_tree, fn {_, deps} -> Enum.empty?(deps) end)
new_dependencies =
Enum.reduce(deps_tree, %{}, fn
{^step, _}, acc -> Map.delete(acc, step)
{other_step, deps}, acc -> Map.put_new(acc, other_step, List.delete(deps, step))
end)
discover_dependencies(new_dependencies, [step | acc])
end
end
# r Day7; :aoc2018 |> :code.priv_dir() |> Path.join("day7.txt") |> Day7.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day7.txt") |> Day7.part2()
input = "Step D must be finished before step E can begin.
Step F must be finished before step E can begin.
Step C must be finished before step A can begin.
Step B must be finished before step E can begin.
Step A must be finished before step D can begin.
Step C must be finished before step F can begin.
Step A must be finished before step B can begin."
# r Day7; Day7.part1(input)
READ MORE
Day 6: Chronal Coordinates - Advent of Code 2018
I did the Advent of Code 2018 day 6 challenge in Elixir! Parts one and two are as follows:
defmodule Day6 do
def part1(input) do
{_infinites, finites} =
input
|> read_input()
|> create_grid()
|> group_by_infinites()
{_coordinates, layout} =
finites
|> Enum.group_by(fn {x, y, _dist} -> {x, y} end)
|> Enum.max_by(fn {_, v} -> length(v) end)
length(layout)
end
def part2(input) do
{max_x, max_y, coordinates} =
input
|> read_input()
for x <- 0..max_x,
y <- 0..max_y do
coordinates
|> Enum.reduce(0, fn {point_x, point_y}, acc ->
distance = abs(x - point_x) + abs(y - point_y)
distance + acc
end)
end
|> Enum.filter(&(&1 < 10_000))
|> Enum.count()
end
defp read_input(input) do
{max_x, max_y, coordinates} =
input
|> File.read!()
|> String.trim()
|> String.split("\n", trim: true)
|> Enum.reduce({-1, -1, []}, fn line, {max_x, max_y, coordinates} ->
[x, y] = String.split(line, ", ")
x = String.to_integer(x)
y = String.to_integer(y)
coordinate = {x, y}
max_x = if x > max_x, do: x, else: max_x
max_y = if y > max_y, do: y, else: max_y
{max_x, max_y, [coordinate | coordinates]}
end)
{max_x, max_y, Enum.reverse(coordinates)}
end
defp create_grid({max_x, max_y, coordinates}) do
for x <- 0..max_x,
y <- 0..max_y do
[{px, py, dist1}, {_, _, dist2} | _] =
Enum.map(coordinates, fn {point_x, point_y} ->
distance = abs(x - point_x) + abs(y - point_y)
{point_x, point_y, distance}
end)
|> Enum.sort_by(fn {_, _, distance} -> distance end)
if dist1 == dist2 do
nil
else
cond do
x == 0 ->
{:infinite, px, py}
x == max_x ->
{:infinite, px, py}
y == 0 ->
{:infinite, px, py}
y == max_y ->
{:infinite, px, py}
true ->
{px, py, dist1}
end
end
end
end
defp group_by_infinites(grid) do
Enum.reduce(grid, {MapSet.new(), []}, fn
nil, acc ->
acc
{:infinite, px, py}, {infinites, finites} ->
{MapSet.put(infinites, {px, py}), finites}
{px, py, dist}, {infinites, finites} ->
if MapSet.member?(infinites, {px, py}) do
{infinites, finites}
else
{infinites, [{px, py, dist} | finites]}
end
end)
end
end
# r Day6; :aoc2018 |> :code.priv_dir() |> Path.join("day6.txt") |> Day6.part1()
# r Day6; :aoc2018 |> :code.priv_dir() |> Path.join("day6.txt") |> Day6.part2()
READ MORE
Day 5: Alchemical Reduction - Advent of Code 2018
I did the Advent of Code 2018 day 5 challenge in Elixir! Parts one and two are as follows:
defmodule Day5 do
def part1(input) do
input
|> read_input()
|> String.codepoints()
|> reduce_polymer()
end
def part2(input) do
chars =
input
|> read_input()
|> String.codepoints()
unit_types =
chars
|> Enum.map(&String.downcase/1)
|> Enum.uniq()
Enum.reduce(unit_types, 1_000_000, fn unit_type, min_size ->
without_unit =
Enum.reject(chars, fn char ->
String.downcase(char) == unit_type
end)
min(min_size, reduce_polymer(without_unit))
end)
end
defp read_input(input) do
input
|> File.read!()
|> String.trim()
end
defp reduce_polymer(chars) do
Enum.reduce(chars, [], fn
char, [] ->
[char]
char, [last_seen | rest] = acc ->
result =
if char != last_seen &&
(char == String.upcase(last_seen) || char == String.downcase(last_seen)) do
rest
else
[char | acc]
end
result
end)
|> length()
end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day5.txt") |> Day5.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day5.txt") |> Day5.part2()
# input = "dabAcCaCBAcCcaDA"
# r Day5; Day5.part2(input)
READ MORE
Day 4: Repose Record - Advent of Code 2018
I did the Advent of Code 2018 day 4 challenge in Elixir! Parts one and two are as follows:
defmodule Day4_1 do
# 1518-11-01 00:00
@log_info ~r/\[(\d+)-(\d+)-(\d+) (\d+):(\d+)\] (.*)/
@guard_entry ~r/Guard #(\d+) begins shift/
def part1(input) do
{_, _, guards} =
input
|> read_input()
|> extract_logs()
{guard_id, _time_asleep} = most_asleep(guards)
{minute, _size} = get_most_asleep_minutes(guards[guard_id])
minute * String.to_integer(guard_id)
end
def part2(input) do
{_, _, guards} =
input
|> read_input()
|> extract_logs()
{guard_id, minute, _size} = most_times_asleep(guards)
minute * String.to_integer(guard_id)
end
defp read_input(input) do
input
|> File.read!()
|> String.split("\n", trim: true)
end
def extract_logs(lines) do
lines
|> Enum.sort()
|> Enum.map(fn line ->
[_year, _month, _day, _hour, minute, message] =
Regex.run(@log_info, line, capture: :all_but_first)
case message do
"falls asleep" ->
{:sleep, String.to_integer(minute)}
"wakes up" ->
{:wake, String.to_integer(minute)}
_ ->
[guard_id] = Regex.run(@guard_entry, message, capture: :all_but_first)
{:guard, guard_id}
end
end)
|> Enum.reduce({nil, nil, %{}}, fn log, {current_guard_id, last_minute, guards} ->
case log do
{:guard, guard_id} ->
{guard_id, nil, Map.put_new(guards, guard_id, [])}
{:sleep, minute} ->
{current_guard_id, minute, guards}
{:wake, minute} ->
new_range = for min <- last_minute..(minute - 1), do: min
{current_guard_id, nil, Map.update!(guards, current_guard_id, &(&1 ++ new_range))}
end
end)
end
defp most_asleep(guards) do
Enum.reduce(guards, {nil, 0}, fn {guard_id, sleep_range}, {_, current_bigger_time} = acc ->
time_asleep = length(sleep_range)
if time_asleep > current_bigger_time do
{guard_id, time_asleep}
else
acc
end
end)
end
defp most_times_asleep(guards) do
Enum.reduce(guards, {nil, 0, 0}, fn {guard_id, asleep_range},
{_current_guard, _minute, max_size} = acc ->
{minute, size} = get_most_asleep_minutes(asleep_range)
if size > max_size do
{guard_id, minute, size}
else
acc
end
end)
end
defp get_minutes_of(guard_intervals) do
{asleep_range, []} =
guard_intervals
|> Enum.reduce({[], []}, fn
{datetime, _}, {range, []} ->
{range, [datetime.minute]}
{datetime, _}, {range, [asleep_time]} ->
new_range = for min <- asleep_time..(datetime.minute - 1), do: min
{[new_range | range], []}
end)
{minute, _size} = get_most_asleep_minutes(asleep_range)
minute
end
defp get_most_asleep_minutes(asleep_range) do
asleep_range
|> Enum.group_by(& &1)
|> Enum.reduce({nil, 0}, fn {minute, occurrences}, {_, times} = acc ->
size = length(occurrences)
if size > times do
{minute, size}
else
acc
end
end)
end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day4.txt") |> Day4_1.part2()
READ MORE
Day 3: No matter how you slice it - Advent of Code 2018
I did the Advent of Code 2018 day 3 challenge in Elixir! Parts one and two are as follows:
defmodule Day3 do
@grid_info ~r/#(\d+) @ (\d+),(\d+): (\d+)x(\d+)/
def part1(input) do
{overlaps, _} =
input
|> read_input()
|> extract_grid()
|> build_map()
|> Enum.reduce({MapSet.new(), MapSet.new()}, fn {x, y, _id}, {overlap, no_overlap} ->
if MapSet.member?(no_overlap, {x, y}) do
{MapSet.put(overlap, {x, y}), no_overlap}
else
{overlap, MapSet.put(no_overlap, {x, y})}
end
end)
MapSet.size(overlaps)
end
def part2(input) do
map =
input
|> read_input()
|> extract_grid()
|> build_keyed_map()
{id, _} =
for {id1, coordinates1} <- map,
{id2, coordinates2} <- map,
id1 != id2 do
overlaps = MapSet.intersection(coordinates1, coordinates2)
if MapSet.size(overlaps) != 0 do
{id1, id2}
else
{id1, nil}
end
end
|> Enum.group_by(fn {key, _} -> key end, fn {_, value} -> value end)
|> Enum.find(fn {_key, overlaps} ->
Enum.all?(overlaps, &Kernel.==(&1, nil))
end)
id
end
defp read_input(input) do
input
|> File.read!()
|> String.split("\n", trim: true)
end
defp extract_grid(lines) do
Enum.map(lines, fn line ->
[id, x, y, width, height] = Regex.run(@grid_info, line, capture: :all_but_first)
[
id,
String.to_integer(x),
String.to_integer(y),
String.to_integer(width),
String.to_integer(height)
]
end)
end
defp build_map(grid) do
Enum.flat_map(grid, fn [id, x, y, width, height] ->
for x <- x..(x + width - 1),
y <- y..(y + height - 1) do
{x, y, id}
end
end)
end
defp build_keyed_map(grid) do
Enum.reduce(grid, %{}, fn [id, x, y, width, height], acc ->
coordinates =
for x <- x..(x + width - 1),
y <- y..(y + height - 1) do
{x, y}
end
Map.put_new(acc, id, MapSet.new(coordinates))
end)
end
end
# :aoc2018 |> :code.priv_dir() |> Path.join("day3.txt") |> Day3.part1()
# :aoc2018 |> :code.priv_dir() |> Path.join("day3.txt") |> Day3.part2()
READ MORE
Day 2: Inventory Management System - Advent of Code 2018
I did the Advent of Code 2018 day 2 challenge in Elixir! Parts one and two are as follows:
defmodule Day2 do
def checksum(input) do
{two, three} =
input
|> read_input()
|> Enum.reduce({0, 0}, fn line, {appears_two_times, appears_three_times} ->
{two_times, three_times, _} =
line
|> String.graphemes()
|> Enum.group_by(& &1)
|> get_checksum_values()
{appears_two_times + two_times, appears_three_times + three_times}
end)
two * three
end
def differ(input) do
lines = input |> read_input()
# length(diff) == 4 # [eq: "_", del: "_", ins: "_", eq: "_"]
for line1 <- lines,
line2 <- lines,
line1 != line2,
diff = String.myers_difference(line1, line2),
length(diff) == 4 do
diff
|> Keyword.get_values(:eq)
|> Enum.join()
end
|> Enum.uniq()
end
defp read_input(input) do
input
|> File.read!()
|> String.split("\n", trim: true)
end
defp get_checksum_values(groups) do
Enum.reduce(groups, {0, 0, MapSet.new()}, fn {_key, chars},
{two_times, three_times, seen} = acc ->
value = length(chars)
if MapSet.member?(seen, value) do
acc
else
new_seen = MapSet.put(seen, value)
case value do
2 -> {two_times + 1, three_times, new_seen}
3 -> {two_times, three_times + 1, new_seen}
_ -> {two_times, three_times, new_seen}
end
end
end)
end
end
:aoc2018 |> :code.priv_dir() |> Path.join("day2.txt") |> Day2.checksum()
:aoc2018 |> :code.priv_dir() |> Path.join("day2.txt") |> Day2.differ()
READ MORE
Day 1: Chronal Calibration - Advent of Code 2018
I did the Advent of Code 2018 day 1 challenge in Elixir! Parts one and two are as follows:
defmodule Day1 do
def frequency(input) do
input
|> read_input()
|> Enum.reduce(0, fn line, acc ->
String.to_integer(line) + acc
end)
end
def repeated_frequency(input) do
input
|> read_input()
|> Stream.cycle()
|> Enum.reduce_while({0, MapSet.new([0])}, fn line, {acc, seen} ->
value = String.to_integer(line) + acc
if MapSet.member?(seen, value) do
{:halt, value}
else
{:cont, {value, MapSet.put(seen, value)}}
end
end)
end
defp read_input(input) do
input
|> File.read!()
|> String.split("\n", trim: true)
end
end
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.frequency()
:aoc2018 |> :code.priv_dir() |> Path.join("day1.txt") |> Day1.repeated_frequency()
READ MORE
Building Blockchain in Elixir
At æternity we chose Elixir to build an alternative implementation of our blockchain protocol. We’ve had a lot of good experiences with this choice, and few bad ones. During the development process we made a lot of internal style and design decisions, in order to both ensure productivity while working collaboratively on the project and also maintain a high quality product. These decisions enable us to to continuously present a great open-source codebase for everybody.
Initial Difficulties
Starting the project from scratch with a new and fairly junior team there were some difficulties. Different developers were used to different code-style guidelines and naming conventions; however as there are few community standards in Elixir, there was no single approach the team could copy. As such, we decided to follow a semantic naming scheme from the beginning to make code as understandable as possible. With the introduction of the Elixir formatter in version 1.6 we chose to use it in the default configuration. Initially, the dynamic typing of the BEAM introduced mistakes in which incorrect structures were passed or data was not pattern matched correctly. We chose to work against this by using precise type definitions and aliases wherever necessary.
Great in Elixir and Design
Overall Elixir struck us as a well-suited language to develop as complex an application as our blockchain implementation. Strong concurrency by design is a great basis to work on top of, to build peer to peer applications. Utilising this we can synchronise our network using the encrypted “noise protocol” and by gossiping or requesting data among nodes worldwide with minimised latency and maximum throughput. The BEAM-provided fault tolerance assists stability; as the network is public for every node to join, it allows our nodes to stay reachable even if attacked. For example, if the component that manages connections to new peers dies unexpectedly due to an overflow in messages from external nodes, it is able to be restarted without affecting the overall state of the node. In various components, such as the connected peers and their status for easy handling or latest blocks, which are frequently accessed, for performance improvements GenServers are used to keep local state for quick access. The fact that Elixir is a modern functional language, with straightforward syntax, made it quite accessible for new developers.
Other helpful features were the powerful native binary operations, which are especially needed in a blockchain implementation, as it deals with lots of binary data to have structures kept as small as possible. An umbrella project structure helps to introduce lower coupling between modules and a good separation of utilities, to name just one thing. Last but not least Elixir provides a great dependency system, with excellent support for various ways to integrate pre-existing features via Nifs, using existing Erlang code or calling binaries via erlexec.
For one of the most critical parts of our blockchain implementation - the consensus rule engine - our team engineered a powerful validation interface, covering any kind of transaction that can occur in the network. The Transaction
module acts as interface for every specialised transaction implementation; it specifies four main callback functions validate
, preprocess_check
, process_chainstate
and deduct_fee
with type specification that can match various transaction and chainstate datatypes.
Every specific transaction structure uses this as behaviour and implements these functions in the correct way, as needed. In case of our SpendTx
, the validate
function checks the validity of structural definitions, for example that the amount sent needs to be greater than 0 and the receiver’s address is only allowed to have an exact number of characters. preprocess_check
will get past the current state of the blockchain and can make additional validations, such as checking if the sending account has sufficient balance to pay for the transaction amount and fee.
If either of these validation steps fails, the transaction is rejected and not processed any further. process_chainstate
applies changes this transaction introduces on the current state of the blockchain; in the case of the spending transaction it subtracts the amount from the sender's account and adds it to the receiver’s account.
Finally, deduct_fee
will subtract the transaction fee from the sender's account. Each specific transaction is enclosed in a wrapping structure that defines its type and calls the implementations function to process the transaction.
This example shows the semantic correct naming and separation of functions, to enable effortless understanding of the functions, if reading code, without looking up the documentation or parameters passed. Using design patterns and structures like these enables us to have flat architecture and avoid deep nesting of code.
The advantages described above and the patterns we use are just a few of the great functionalities that Elixir enables and which help us to build better code, resulting in a scalable and maintainable blockchain platform. To find out more about æternity visit the work-in-progress open source repository of the elixir implementation https://github.com/aeternity/elixir-node or our protocol definition https://github.com/aeternity/protocol.
READ MORE
Kate Travers’ Journey from Art shipping to Elixir Senior Engineer
Kate’s route to becoming a developer was not the usual one. She started out in art history working for an art shipping company in New York. Five years in, with a lot of the work still being done on pen and paper, her employer decided to hire contractors to build a proper logistics system. Kate immediately clicked with this team of contractors and went from their internal stakeholder on the project to beta testing the new system and finally joining them directly as a support technician.
Kate just loved it and wanted to do more, resulting in her taking a course at the Flatiron school. This thorough education in programming resulted in her joining the Flatiron engineering team as an apprentice, and almost four years on, she is now one of their senior developers.
Kate is building ‘learn.co,’ a learning management system with added interactivity and community features. The system only needs one click to “Open IDE” and launch a functional development environment right in the browser. Flatiron are particularly excited about this feature because it allows students new to coding to get a taste of programming with real tools that developers use on the job. Unlike a REPL (a read-eval-print-loop) that executes a few lines of simple code, the IDE allows students to experience the more complex interaction between editing different files and executing them from a command line, all in browser. The full write-up can be viewed here. Flatiron has been using Elixir in production since 2016, with 3 apps, the main one being the backend that powers this custom IDE. Their team is hiring engineers, especially Elixir devs, based in NYC, but they do support remote roles too.
Kate feels that the biggest hurdle she had to overcome was ‘the imposter syndrome.’ The Ruby and Elixir communities were very supportive of her but it was only after giving her first talk at Full Stack Toronto 2016, that she finally felt like she had overcome these self doubts. Holding the attention of fellow developers for an hour and answering their questions, helped to change her perception of her own skills, infusing a level of self confidence.
Why Elixir?
Kate’s talk at Code Elixir LDN 2018 will be about ‘Pattern matching: The gateway to loving Elixir.’ For Kate, it's what won her over to the language. Elixir has a lot going for it, concurrency, fault tolerance, scalability, yet none of these can be enjoyed right away. Only after the app is made and in production do you get to see just what this means. When starting out in a new language, you need a quick win, the thing that will keep you going, for Kate, this was ‘Pattern Matching.’
Pattern Matching is a deceptively powerful paradigm making Elixir a compelling language to program in. It does so much more than just help developers write small, declarative, maintainable functions; it actually makes developers stronger programmers. To understand what this is in Elixir, requires a reframing of the way tying values to variables is thought about. The statement x = 1, the = is the “match operator”, and evaluates whether the value on the right matches the pattern on the left. If it is a match, then the value is bound to the variable, if not, then a MatchError is raised. Attend Kate's talk at Code Elixir LDN and get a good grounding in this attractive feature, also read Kate’s in-depth exploration of this on her blog here.
Kate’s Bio
Kate Travers is a Brooklyn-based fullstack web developer, specialising in Rails, React, and Elixir applications. Outside work, Kate is an active volunteer, tutor and mentor through Flatiron School, as well as backup quarterback for the three-time-defending champions of the Brooklyn co-ed touch football league.
READ MOREElixir powers first Car Share Service from Toyota
Toyota has just launched its first global car sharing platform, operated by Servco Pacific, Toyota’s distributor in Hawaii. The Hui service utilises Toyota’s proprietary global Mobility Service Platform (MSPF) and a consumer facing app.
Hui offers a new round-trip, station-based car share program, available to users 24/7. Seventy Toyota and Lexus vehicles are available for reservation through the Hui mobile app, by the hour or day at 25 easily accessible locations throughout Honolulu. The vehicles initially in the program include the Toyota Prius, Prius Prime, Camry XSE, as well as Lexus RX 350 and RX F Sport vehicles. Hui vehicles are parked in marked, reserved stalls for easy pick-up and drop-off.
The app supports a range of fleet management tools, as well as driver authentication and payment management. In addition, Hui vehicles are equipped with Toyota’s Smart Key Box, which generates a digital key that allows users to lock and unlock, as well as start vehicles via their smartphone.
Toyota Connected and Servco developed the service together as one of the first public applications of MSPF, the core ecosystem for leveraging the potential of connected vehicle systems to support the development of new mobility businesses – such as car-sharing, ride-sharing and remote delivery.
Toyota Connected is using Elixir as part of the backend system that makes up MSPF. It provides the API for mobile and web applications, as well as doing the geo processing such as whether a vehicle is inside or outside a geofence.
To learn more about how Toyota Connected is using Elixir, watch the following videos:
- Toyota's Shared Component Library - Tony Ward - EmberConf 2018
- Streaming GIS - Lightning talk, ElixirConf 2017
- Elixir with Kafka - Mathew Gardner - ElixirConf 2017
- Managing state in distributed Elixir - Jerel Unruh - Lonestar ElixirConf 2018
- Elixir - The Toyota Way - Powell Kinney - ElixirConf 2017
By 2020, Toyota Connected plan to have most new vehicles sold in North America and Japan sending information to their cloud. Analysing traffic patterns, driver behaviour and connecting drivers with infrastructure and other information is only part of what Toyota Connected will do, as it focuses on creating new services and products to keep the car as a beloved companion.
Powell Kinney, Chief product owner at Toyota Connected, will be giving a keynote at Code Elixir LDN, 16 August 2018. His talk will be on ‘Elixir for the Long Haul.’
He will discuss designing for longevity with Elixir and Erlang/OTP for a platform that will empower mobility at the global scale for years to come. His talk will focus on the challenges companies face when shifting from a software focus to platform focus, and what it will require in terms of the day-to-day implications for developers.
Toyota Connected’s approach to software development empowers teams to build for the long-term while still being able to adapt to changing features. The challenge for developers will be maintaining an ever-growing platform in the face of a rapidly changing mobility landscape. At the same time, Toyota Connected is interested in building a platform that powers more than just a single mobility use case—that instead provides for the whole range of mobility services.
There is still time to register for Code Elixir LDN.
READ MOREFrom a web application to a distributed system
This article is an introduction to Gianluca Padovani’s talk at Code BEAM STO, on how to develop a web application that can scale to a distributed system.
Why this talk at Code BEAM STO?
Gianluca compares conference presentations to software and bananas, they rot if we do not take care of them. His Stockholm talk will update his Milan talk, as well as the code-base that both of them refer to. Gianluca plans to eventually create a workshop about this topic once complete, that can help new developers familiarise themselves with these concepts.
In the Beginning…
In the beginning, web development was very “simple,” there was a web server, a bunch of scripts and a database. Every single http request was translated into SQL queries that loaded or wrote data in a DB, the result was often the creation of a HTML page and nothing more. If we were in a “complex environment” we had some background tasks powered often by something similar to cron. Our DB was the truth and everything was in a single place, everything had a beginning (the arrival of the http request) and an end (the delivery of the http response).
This procedure developed a development attitude where we created all the related objects (we were probably adopting an OOP language) at the beginning of our work and we destroyed everything at the end. We were “ not allowed” to keep data and object in memory because everything started and finished with the life of the http request.
However, over time, the web became a platform to develop “applications” where the state cannot be kept in a single database and in a single process (you may hear a little voice whispering “microservices” …). Operations now span the length of a single http request and we now need the ability to communicate with a lot of different systems and keep track of their states.
There is currently a lot of interest in how these problems are solved in the BEAM environment (using Actor model) and how some common patterns like Supervisor or GenServer are used in other languages or frameworks, Akka for example. Gianluca has been developing software since the last millennium and has seen a lot of patterns and development models rise and fall. There’s a saying in Italy “paese che vai usanza che trovi” (when in Rome do as the Romans do) and this holds true with programming too, there are patterns that the newbies need to learn. For those who are coming to the BEAM ecosystem through Elixir they are indeed lucky, because they will find they are able to take advantages of Erlang and the BEAM virtual machine’s patterns, which are already ‘battle hardened’ from over 20 years of development history.
About Gianluca Padovani’s Code BEAM STO talk
How can we create a web application that takes advantage of the characteristics of the BEAM using the resources of a single node and eventually scale this to a multi-node application?
Gianluca Padovani will be giving the talk ‘From a web application to a distributed system’ at Code BEAM STO. In this talk, he will be creating a simple e-commerce system that will expose some classic distributed system problems that will be resolved using patterns from the BEAM.
If you want to have a heads-up before the talk, you can dig into the code that the talk will be based on, here is the repo and here is the link of the talk that Gianluca did in Milan. You can also follow him on Medium.
READ MOREWhy should Elixir developers get familiar with Erlang and the BEAM at Code BEAM STO?
Elixir, Erlang and LFE certainly have different features but they all share a foundation that carries the same ideas, techniques and patterns. Having familiarity with each technology is a major strength: it allows you to tap into a wider ecosystem and get the best out of every technology. Even if you end up using only one language in your day to day development, that knowledge will be useful in giving you more tools to reason with and to solve problems efficiently.
If you work with Elixir and Phoenix, you could benefit by spending some time looking at Cowboy. Conversely, if you have to interact with databases from Erlang you could look at how Elixir and Ecto approach the problem.
Which is why there is a lot for Elixir developers to shout about at Code BEAM STO this year! Not only are there 12 talks focusing on Elixir alone, but numerous other talks, 50+ in total, that are super relevant for Elixir developers. Ultimately, the BEAM community is one, no matter what language is used. Elixir talks at Code BEAM STO are listed below, plus a taster of a few other relevant highlights.
We will be joined by three members of the Elixir core team, Eric Meadows-Jönsson, Michal Muskala and Andrea Leopardi.
**Ecto - Database library for Elixir - **Eric Meadows-Jönsson
Ecto is a popular database library for Elixir and was one of its first major libraries. Eric will discuss Ecto's capabilities, delve into some of its inner workings, driven by code examples, he will explain what sets Ecto apart from traditional ORMs and database frameworks.
**Optimising for the BEAM - **Michal Muskala
Michal will explore some common techniques for optimising programs running on the BEAM, applicable to Elixir, Erlang and LFE. He’ll showcase the tools used for evaluating performance and for discovering bottlenecks.
**Update: Elixir core dev team - **Andrea Leopardi,
Andrea will give an update on what projects the Elixir core team have been working on, what's being researched, as well as what new features can be expected in the next Elixir release.
Taking it to the metal - Sonny Scroggin
In this talk Sonny, a Phoenix core team member, will discuss Native Implemented Functions (NIFs) - Erlang's Foreign Function Interface (FFI). He will show how to build performance-critical functionality in Erlang/Elixir with Rust, whilst showing how to avoid the pitfalls of writing native code.
Crypto + Concurrency Anna Neyzberg
We all know that OTP is an important part of the Elixir ecosystem, but do we know why? How does it work in relation to Elixir? Anna, co-founder of ElixirBridge, will show how to leverage OTP to build highly concurrent systems that scale. In-order to see OTP at work, she will add load to a real time crypto-currency exchange.
Raxx; refined web development - Peter Saxton
Peter will Introduce Raxx, as an alternative to Plug in the Elixir eco-system. More generally, he will explore why functional purity is valuable in the Erlang/Elixir world and how a different conceptual model can lead to a completely different solution to the same problem.
How Elixir helped us change Ukrainian healthcare system - Alex Troush
Alex will delve into the caveats behind large-scale development with Elixir. Detailing how they used it for the Ukrainian Health Services, one of the biggest open-source Elixir projects in the world.
Sagas of Elixir - Andrew Dryga
Andrew will show alternative approaches for dealing with interactions with remote services that create side effects. He will present a new open source package - Sage, explaining what use cases it covers.
From a web application to a distributed system - Gianluca Padovani
In this talk, Gianluca will explain how using the BEAM and Elixir to create a better application can start from a simple web application and then became a more complex distributed system.
Simple is beautiful: Building an SLA monitoring tool at PagerDuty - Aish Dahal
Aish will explain how he built an Elixir powered monitoring tool that used Kafka not only as a communication layer but also as a storage layer. He will show how they replaced a complex in-house monitoring tool with a simpler and more reliable/scalable one using Elixir/OTP.
Stateful webhooks: what are they good for? - Nathan Herald
Webhooks are super powerful in connecting desperate services, but what can we do when webhook functions have memory? How does one persist state in a distributed webhooks system? Nathan, from Microsoft, will explain, give some examples and live code a game using Elixir and Javascript.
Expressive power in Elixir - Joseph Yiasemides
Joseph will show how to become s better Elixir user by exploiting the 'module' to its fullest extent.
There are so many more super relevant talks at Code BEAM STO for Elixir developers, view them all here. A few of the highlights are listed below.
Keynote: A genealogy of functional programming - Osa Gaius
Join Osa Gaius on a journey through the history of functional programming, of Erlang and Elixir more specifically. It begins with Lambda Calculus, and charts a path to the present moment. The future success of Erlang and Elixir will be marked by how we learn from the history of functional programming. Based on real-world experiences and historical analysis, Osa will then look to the future, giving some ideas on how to increase Erlang and Elixir language adoption which centers around community-building.
Erlang/OTP team update - Kenneth Lundin
Every year, the Ericsson Erlang/OTP team give an update on what they have been developing and what they have their eyes on for the future.
Getting to the BEAM, without going through Erlang - Kofi Gumbs
Using Erlang to create a language for the BEAM is well-modeled, with projects like Elixir, LFE, and Alpaca growing in popularity and maturity. In this talk, Kofi will discuss the making of a compile-to-BEAM language, from scratch. He will give a guided tour through codec-beam, a BEAM assembler written in Haskell, which provides an explicit model for the BEAM's semantics. He’ll finally compare this project to the Erlang compiler's assembler, and see if OTP can be beaten at it's own game.
Clojure on the BEAM - Juan Facorro
Following the theme of language implementation on the BEAM, Juan will explain the process of implementing an already existing language on the BEAM, explaining the challenges this involves and reviewing the results he has achieved.
View all 50+ speakers and talks here.
READ MORE