How to make a program that prints number from 1 to N starting in 1 without an accumulator?

I want to make a program to prints number from 1 to N starting in 1 without an accumulator.

defmodule Recursion do
  def print_multiple_times(n) when n <= 1 do
    IO.puts n
  end

  def print_multiple_times( n) do
    IO.puts n
    print_multiple_times( n - 1)
  end
end

I want to do something like this, but instead of going from n to 1 (n - 1) going from 1 to n, but without an accumulator I can’t find any solution.

iex> for n <- 1..10, do: IO.puts n

or

defmodule Recursion do
  def print_multiple_times(n) when n >= 10 do
    IO.puts n
  end

  def print_multiple_times( n) do
    IO.puts n
    print_multiple_times( n + 1)
  end
end

but in this case, You set n as starting point. You could pass m value as the end point.

1 Like

Thanks it worked, I thought there wasn’t for loops on Elixir

It’s not a loop, it’s a list comprehension

https://elixir-lang.org/getting-started/comprehensions.html

3 Likes

Other esoteric ways, just for fun:

Enum.each(1..10, &IO.puts/1)

Stream.iterate(0, & (&1 + 1)) |> Stream.take(10) |> Enum.join(" ") |> IO.puts

Stream.iterate(0, & (&1 + 1)) |> Stream.map(&IO.puts/1) |> Enum.take(10)

2 Likes

This is not esoteric, but the only true way, as all the other versions actually create a list that we are not interested in. Since we are only interested in the side effects of printing, actually only Enum.each/2 or some stream that is piped into Stream.run/1 are valid answers.

Yes, perhaps “esoteric” was not my best choice of words. I get the feeling the original poster was trying various approaches out and there was no strict constraint. If there was a constraint to not create a list, then I apologize for my irrelevant post. At least I didn’t use an accumulator :man_shrugging:

Why?

Additional parameters are a legitimate technique for controlling recursion. With tail recursion (without side effects like IO.puts) one parameter is used to managing the data that is left on the call stack with body recursion.

defmodule Demo do
  def multi(n),
    do: multi(1, n, [])

  defp multi(i, n, list) when i > n,
    do: list

  defp multi(i, n, rest) when i <= n,
    do: multi(i + 1, n, [i | rest])
end

result = Demo.multi(10)
IO.puts("#{inspect(result, charlists: :as_lists)}")

r = :lists.reverse(result)
IO.puts("#{inspect(r, charlists: :as_lists)}")
$ elixir demo.exs
[10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
$

Myth: Tail-Recursive Functions are Much Faster Than Recursive
Erlang’s Tail Recursion is Not a Silver Bullet

1 Like

I didn’t mean to scare you away, sorry if I did. I’m not sure if the original poster needed a list, but from the example code, the Enum.each/2 is closest.

Because it sometimes can help understanding the language if one sees a couple different ways to achieve the same or similar observable behaviour?

1 Like
1..n |> Enum.map(&to_string/1) |> Enum.intersperse("\n") |> IO.puts()

I was driving towards the realization that the original code has in fact a hardcoded limit - as demonstrated by @kokolegorille.

So going the other way doesn’t actually need an additional parameter. It’s just that the original code left one out by hardcoding it.

defmodule Recursion do
  def print_multiple_times(n, m) when n <= m do
    IO.puts(n)
  end

  def print_multiple_times(n, m) do
    IO.puts(n)
    print_multiple_times(n - 1, m)
  end

  def print_multiple_times_r(n, m) when n >= m do
    IO.puts(n)
  end

  def print_multiple_times_r(n, m) do
    IO.puts(n)
    print_multiple_times_r(n + 1, m)
  end

  def multi(n, m) when n >= m,
    do: print_multiple_times(n, m)

  def multi(n, m),
    do: print_multiple_times_r(n, m)
end

Recursion.multi(10, 1)
Recursion.multi(1, 10)
Recursion.multi(10, 10)

Yeah, the Enum.each/2 was closest, but honestly, I like @kokolegorille 's example for comprehension most. As I learned from José’s Advent of Code videos, a for comprehension that is not assigned to a variable does not generate the intermediate list either.