Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Infinite loop with counter in elixir

I'm studying functional programming and I want to implement something like this.

while(true) do
  if(somethingHappensHere) {
    break
  }
  counter++
end
return counter

How can I do this in functional way using elixir?

Thanks for this.

like image 443
Renato Cassino Avatar asked Dec 23 '17 15:12

Renato Cassino


3 Answers

While in most functional programming languages one would use a recursion for this task, Elixir particularly provides the way to do this without using an explicit recursion call: Enum.reduce_while/3:

Enum.reduce_while(1..100, 0, fn i, acc ->
  if condition, do: {:halt, acc}, else: {:cont, acc + i}
end)

For lazy evaluation one would use Stream.reduce_while/3.

To make it infinite, one might use one of infinite generators, provided by Stream module, like Stream.iterate/2:

Stream.iterate(0, &(&1+1)) |> Enum.reduce_while(0, fn i, acc ->
  if i > 6, do: {:halt, acc}, else: {:cont, acc + 1}
end)
#⇒ 7

For the sake of recursion, this is how the recursive solution might be implemented in Elixir:

defmodule M do
  def checker, do: & &1 <= 0
  def factorial(v, acc \\ 1) do
    if checker().(v), do: acc, else: factorial(v - 1, v * acc)
  end
end

M.factorial 6                            
#⇒ 720
like image 62
Aleksei Matiushkin Avatar answered Nov 09 '22 10:11

Aleksei Matiushkin


Not sure about elixir specifically, but you can achieve this using recursion:

function myFunction(int counter)
{
  if (condition) {
    return counter
  }
  return myFunction(counter + 1)
}

This essentially sets up a function that can infinitely recurse (call itself), each time passing in the next counter value.

By having the recursive call as the last thing the function does, this is known as tail-call recursion which elixir supports (as per: Does Elixir infinite recursion ever overflow the stack?)

This can then be used as such:

int counterValue = myFunction(0)

With the function only returning once the condition is true.

You could also make this more generic by having the function take another function that returns true or false (i.e. performs the conditional check).

As I said, unfortunately I'm not aware of the syntax of elixir, but I'm sure you'll be able to bridge that gap.

like image 1
Clint Avatar answered Nov 09 '22 09:11

Clint


An example of something in Elixir syntax:

defmodule SOQuestion do 
  def test(counter) do
    if (something_happens_here?()), do: counter, else: test(counter+1)
  end
  def something_happens_here?() do
    true
  end
end

And it would be invoked like this:

SOQuestion.test(0)

A couple of notes on this:

1.) It's a code fragment. Obviously it's tough to be very complete given the broad nature of your question.

2.) something_happens_here? being a predicate it would normally be named ending with a question mark.

3.) If something_happens_here? were defined in a different module, then the call would be if (Module.something_happens_here?())

4.) I've obviously coded something_happens_here? to simply return true unconditionally. In real code, of course, you'd want to pass some argument to something_happens_here? and act on that to determine which boolean to return.

Given all that I totally agree with @mudasowba--this sort of thing is usually better handled with one of the higher order functions built into the language. It's less error prone and often much easier for others to read too.

like image 1
Onorio Catenacci Avatar answered Nov 09 '22 08:11

Onorio Catenacci