defmodule School do @moduledoc """ Simulate students in a school. Each student is in a grade. """ @type school :: any() @doc """ Create a new, empty school. """ @spec new() :: school def new(), do: %{} @doc """ Add a student to a particular grade in school. """ @spec add(school, String.t(), integer) :: {:ok | :error, school} def add(school, name, grade) do if Enum.any?(roster(school), &(&1 == name)) do {:error, school} else {:ok, Map.put(school, grade, [name | Map.get(school, grade, [])])} end end @doc """ Return the names of the students in a particular grade, sorted alphabetically. """ @spec grade(school, integer) :: [String.t()] def grade(school, grade) when not is_map_key(school, grade), do: [] def grade(school, grade), do: Enum.sort(Map.get(school, grade)) @doc """ Return the names of all the students in the school sorted by grade and name. """ @spec roster(school) :: [String.t()] def roster(school) do for grade <- Enum.sort(Map.keys(school)), reduce: [] do acc -> acc ++ grade(school, grade) end end end