Created
February 16, 2021 21:09
-
-
Save kevinkirkup/dc9b15ea75001282e77e4e42eb24bbba to your computer and use it in GitHub Desktop.
Exercise 4.2
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule Exercise42 do | |
@moduledoc """ | |
Documentation for `Exercise 4.2`. | |
""" | |
require IO | |
def sort(values) do | |
router = create_router() | |
Enum.each(values, fn v -> send(router, {:int, v}) end) | |
send(router, {:get_results, self()}) | |
receive do | |
{:result, result} -> result | |
end | |
end | |
defp create_router() do | |
spawn(Exercise42, :router_init, []) | |
end | |
def router_init() do | |
# Create a process running worker_loop/1 for each integer in the range 1 - 9 | |
workers = Enum.reduce(1..9, %{}, &Map.put_new(&2, &1, spawn(Exercise42, :worker_loop, [[]]))) | |
router_loop(workers) | |
end | |
def router_loop(workers) do | |
receive do | |
{:int, n} -> | |
# Find the correct worker and send it a value message | |
send(workers[n], {:value, n}) | |
router_loop(workers) | |
{:get_results, sender} -> | |
results = | |
Map.keys(workers) | |
# Sort workers in ascending order so the final list is in the correct order | |
|> Enum.sort() | |
# Ask each worker for their values | |
|> Enum.flat_map(&get_worker_results(workers[&1])) | |
IO.inspect(results, label: "Router Loop") | |
# Send results to sender and exit | |
send(sender, {:result, results}) | |
end | |
end | |
def get_worker_results(worker_pid) do | |
# Send worker a message asking for results | |
send(worker_pid, {:get_results, self()}) | |
# Receive worker's reply, tell it to shut down and return the worker's values | |
receive do | |
{:results, values} -> | |
send(worker_pid, {:shutdown}) | |
values | |
end | |
end | |
def worker_loop(values) do | |
receive do | |
# Handle messages adding a new value | |
{:value, n} -> | |
worker_loop([n | values]) | |
# Handle messages requesting values | |
{:get_results, sender} -> | |
send(sender, {:results, values}) | |
worker_loop(values) | |
# Handle shut down message | |
{:shutdown} -> | |
exit(:normal) | |
end | |
end | |
def random_ints(n), do: random_ints(n, []) | |
defp random_ints(0, accum), do: accum | |
defp random_ints(n, accum) do | |
random_ints(n - 1, [:random.uniform(9) | accum]) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment