无限循环与计数器在不老长寿

问题描述 投票:3回答:4

我正在学习函数式编程,我想实现这样的东西。

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

如何使用elixir以功能方式完成此操作?

谢谢你。

functional-programming elixir
4个回答
6
投票

虽然在大多数函数式编程语言中,人们会使用递归来完成此任务,但Elixir特别提供了在不使用显式递归调用的情况下执行此操作的方法:Enum.reduce_while/3

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

对于懒惰的评估,人们会使用Stream.reduce_while/3

为了使它无限,可以使用由Stream模块提供的无限生成器之一,如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

为了递归,这是在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

1
投票

不确定elixir,但你可以使用递归实现这一点:

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

这基本上设置了一个函数,每次传入下一个计数器值时都可以无限递归(调用自身)。

通过将递归调用作为函数执行的最后一项操作,这称为elixir支持的尾调用递归(根据:Does Elixir infinite recursion ever overflow the stack?

然后可以这样使用:

int counterValue = myFunction(0)

该功能仅在条件为真时返回。

您还可以通过使该函数采用另一个返回true或false的函数(即执行条件检查)来使其更通用。

正如我所说,不幸的是我不知道长生不老药的语法,但我相信你能够弥合这个差距。


1
投票

Elixir语法中的一个例子:

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

它将被调用如下:

SOQuestion.test(0)

关于这个的几点说明:

1.)这是一个代码片段。显然,鉴于你的问题的广泛性,很难完全。

2.)something_happens_here?是一个谓词,它通常被命名以问号结尾。

3.)如果something_happens_here?在不同的模块中定义,那么调用将是if (Module.something_happens_here?())

4.)我显然已经将something_happens_here?编码为无条件地返回true。当然,在实际代码中,您需要将一些参数传递给something_happens_here?并对其进行操作以确定返回哪个布尔值。

鉴于我完全同意@ mudasowba的所有内容 - 通常使用语言中内置的高阶函数之一处理这种事情。它不易出错,并且通常也更容易让其他人阅读。


0
投票

如上所述,您可以使用许多内置函数,如Enum.reduce_while/3。但是,有时使用简单递归同样简单(或有趣)。

Using recursion:

我将做一些通用的例子,并使用bar(foo)作为你的somethingHappensHere条件的一个例子。

1) If bar(foo) is something allowed in a guard clause:

defmodule Counter do
  def count do
    count(foo, 0)
  end

  defp count(foo, count) when bar(foo), do: count

  defp count(foo, count), do: count(foo, count + 1)
end

2) If bar(foo) is a function that returns a boolean:

defmodule Counter do
  def count(foo) do
    count(foo, 0)
  end

  defp count(foo, count) do
    if bar(foo) do
      count
    else
      count(foo, count + 1)
    end
  end
end

3) If bar(foo) returns something other than a boolean, that you can pattern-match on, like:

defmodule Counter do
  def count(foo) do
    count(foo, 0)
  end

  defp count(foo, count) do
    case bar(foo) do
      {:ok, baz}  -> count
      {:error, _} -> count(foo, count + 1)
    end
  end
end

调用模块和功能:

Counter.count(foo)
© www.soinside.com 2019 - 2024. All rights reserved.