         {&Enumerable.reduce(enum, &1, step), [], :cont}
       end)
 
-    do_zip(enum_funs, acc, fun, zip_fun)
-  end
-
-  # This implementation of do_zip/4 works for any number of streams to zip
-  defp do_zip(zips, {:halt, acc}, _fun, _zip_fun) do
+    do_zip_enum(enum_funs, acc, fun, zip_fun)
+  end
+
+  # This implementation of do_zip_enum/4 works for any number of streams to zip
+  defp do_zip_enum(zips, {:halt, acc}, _fun, _zip_fun) do
     do_zip_close(zips)
     {:halted, acc}
   end
 
-  defp do_zip(zips, {:suspend, acc}, fun, zip_fun) do
-    {:suspended, acc, &do_zip(zips, &1, fun, zip_fun)}
-  end
-
-  defp do_zip([], {:cont, acc}, _callback, _zip_fun) do
+  defp do_zip_enum(zips, {:suspend, acc}, fun, zip_fun) do
+    {:suspended, acc, &do_zip_enum(zips, &1, fun, zip_fun)}
+  end
+
+  defp do_zip_enum([], {:cont, acc}, _callback, _zip_fun) do
     {:done, acc}
   end
 
-  defp do_zip(zips, {:cont, acc}, callback, zip_fun) do
+  defp do_zip_enum(zips, {:cont, acc}, callback, zip_fun) do
     try do
-      do_zip_next_tuple(zips, acc, callback, [], [], zip_fun)
+      do_zip_next(zips, acc, callback, [], [], zip_fun)
     catch
       kind, reason ->
         do_zip_close(zips)
         :erlang.raise(kind, reason, __STACKTRACE__)
     else
       {:next, buffer, acc} ->
-        do_zip(buffer, acc, callback, zip_fun)
+        do_zip_enum(buffer, acc, callback, zip_fun)
 
       {:done, _acc} = other ->
         other
     end
   end
 
-  # do_zip_next_tuple/6 computes the next tuple formed by
+  # do_zip_next/6 computes the next tuple formed by
   # the next element of each zipped stream.
-  defp do_zip_next_tuple(
+  defp do_zip_next(
          [{_, [], :halt} | zips],
          acc,
          _callback,

  """
  @spec zip(Enumerable.t(), Enumerable.t()) :: Enumerable.t()
  def zip(enumerable1, enumerable2) do
    zip([enumerable1, enumerable2])
  end

  @doc """
  Lazily zips corresponding elements from two enumerables into a new one, transforming them with
  the `zip_fun` function as it goes.

  The `zip_fun` will be called with the first element from `enumerable1` and the first
  element from `enumerable2`, then with the second element from each, and so on until
  either one of the enumerables completes.

  ## Examples

      iex> concat = Stream.concat(1..3, 4..6)
      iex> Stream.zip_with(concat, concat, fn a, b -> a + b end) |> Enum.to_list()
      [2, 4, 6, 8, 10, 12]

  """
  @doc since: "1.12.0"
  @spec zip_with(Enumerable.t(), Enumerable.t(), (term, term -> term)) :: Enumerable.t()
  def zip_with(enumerable1, enumerable2, zip_fun) when is_function(zip_fun, 2) do
    zip_with([enumerable1, enumerable2], &apply(zip_fun, &1))
  end

  @doc """

  end

  @doc """
  Lazily zips corresponding elements from two enumerables into a new one, transforming them with
  the `zip_fun` function as it goes.

  The `zip_fun` will be called with the first element from `enumerable1` and the first
  element from `enumerable2`, then with the second element from each, and so on until
  either one of the enumerables completes.

  ## Examples

      iex> concat = Stream.concat(1..3, 4..6)
      iex> Stream.zip_with(concat, concat, fn a, b -> a + b end) |> Enum.to_list()
      [2, 4, 6, 8, 10, 12]

  """
  @doc since: "1.12.0"
  @spec zip_with(Enumerable.t(), Enumerable.t(), (term, term -> term)) :: Enumerable.t()
  def zip_with(enumerable1, enumerable2, zip_fun)
      when is_list(enumerable1) and is_list(enumerable2) and is_function(zip_fun, 2) do
    &zip_pair(enumerable1, enumerable2, &1, &2, zip_fun)
  end

  def zip_with(enumerable1, enumerable2, zip_fun) when is_function(zip_fun, 2) do
    zip_with([enumerable1, enumerable2], fn [left, right] -> zip_fun.(left, right) end)
  end

  defp zip_pair(_list1, _list2, {:halt, acc}, _fun, _zip_fun) do
    {:halted, acc}
  end

  defp zip_pair(list1, list2, {:suspend, acc}, fun, zip_fun) do
    {:suspended, acc, &zip_pair(list1, list2, &1, fun, zip_fun)}
  end

  defp zip_pair([], _list2, {:cont, acc}, _fun, _zip_fun), do: {:done, acc}
  defp zip_pair(_list1, [], {:cont, acc}, _fun, _zip_fun), do: {:done, acc}

  defp zip_pair([head1 | tail1], [head2 | tail2], {:cont, acc}, fun, zip_fun) do
    zip_pair(tail1, tail2, fun.(zip_fun.(head1, head2), acc), fun, zip_fun)
  end

  @doc """
  Lazily zips corresponding elements from a finite collection of enumerables into a new
  enumerable, transforming them with the `zip_fun` function as it goes.

