How to invoke a tail-call loop expression like Clojure's loop?

Having 2-element Tuple as acc is not a shame. Many reduce-based solutions written by senior developers are using it. Your code is really good enough. :+1:

However there is other way to write same code. You can use a simple pattern matching solution, for example:

defmodule Example do
  # function header with default arguments
  def sample(files, bookmarks \\ "", counter \\ 1)

  # when done return only bookmarks string
  def sample([], bookmarks, _counter), do: bookmarks

  # tail recursion
  def sample([file | files], acc_bookmarks, acc_counter) do
  	# your logic goes here, for example
  	{file_bookmarks, file_counter} = process_file(file)
  	# recursively call this for rest files with updated bookmarks and counter
  	sample(files, acc_bookmarks <> file_bookmarks, acc_counter + file_counter)
  end
end

Personally I like separating accumulation and process logic, as in example above, which makes the code more clear.