Using Stream.cycle/1 as a do while routine

Hi.
So I know this problem can be solved using recursion so I’m just asking it out of curiosity. I’ve been reading about implementing loop-like behaviours using Stream in Elixir and I’m trying to use Stream.cycle/1 to do this:

Generate random numbers between 1 and 20, and stop generating them after the value 20 has been generated. This is how I wanted to solve it:

numbers = for _ <- 1..20, do: :rand.uniform(20)
Stream.cycle(numbers) |> Enum.take_while(fn x -> x != 20) |> Enum.to_list

But this never returns. Is there a way to accomplish this with Stream ?

@crisefd your version fails because numbers is a concrete list of numbers, not a function that generates a random number a infinite number of times. This is to say it does this:

iex(1)> numbers = for _ <- 1..20, do: :rand.uniform(20)
[2, 6, 6, 17, 8, 7, 1, 8, 19, 8, 9, 18, 7, 3, 16, 2, 2, 7, 19, 18]

As you can see, it’s entirely possible to not get a 20 in that list. Stream.cycle then goes through that list forever trying to supply a 20 to Enum.take_while.

You want to use https://hexdocs.pm/elixir/Stream.html#repeatedly/1

iex(2)> Stream.repeatedly(fn -> :rand.uniform(20) end) |> Enum.take_while(fn x -> x != 20 end)
[19, 3, 16, 11, 8, 12, 2, 9, 15, 9, 10, 9, 16, 11, 5, 3, 9, 9, 6, 3, 16, 12, 8,
 3, 3, 14, 18, 9, 6, 19, 8, 12, 3, 16, 13, 16, 4, 7, 17, 9, 7, 12, 14, 9, 16,
 13, 12, 2]
3 Likes

Nice, very clean.
Thank you