   """
   @spec min_by(t, (element -> any), (() -> empty_result)) :: element | empty_result
         when empty_result: any
-  def min_by(enumerable, fun, empty_fallback \\ fn -> raise Enum.EmptyError end) do
+  def min_by(enumerable, fun, empty_fallback \\ fn -> raise Enum.EmptyError end)
+      when is_function(fun, 1) and is_function(empty_fallback, 0) do
     first_fun = &{&1, fun.(&1)}
 
     reduce_fun = fn entry, {_, fun_min} = old ->

        when empty_result: any
  def min_max(enumerable, empty_fallback \\ fn -> raise Enum.EmptyError end)

  def min_max(first..last, _empty_fallback) do
    {Kernel.min(first, last), Kernel.max(first, last)}
  end

  def min_max(enumerable, empty_fallback) do
    first_fun = &{&1, &1}

    reduce_fun = fn entry, {min, max} ->


  """
  @spec max(t, (() -> empty_result)) :: element | empty_result when empty_result: any
  def max(enumerable, empty_fallback \\ fn -> raise Enum.EmptyError end)
      when is_function(empty_fallback, 0) do
    aggregate(enumerable, &Kernel.max/2, empty_fallback)
  end

