我正在学习函数式编程,我想实现这样的东西。
while(true) do
if(somethingHappensHere) {
break
}
counter++
end
return counter
如何使用elixir以功能方式完成此操作?
谢谢你。
虽然在大多数函数式编程语言中,人们会使用递归来完成此任务,但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
不确定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的函数(即执行条件检查)来使其更通用。
正如我所说,不幸的是我不知道长生不老药的语法,但我相信你能够弥合这个差距。
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的所有内容 - 通常使用语言中内置的高阶函数之一处理这种事情。它不易出错,并且通常也更容易让其他人阅读。
如上所述,您可以使用许多内置函数,如Enum.reduce_while/3
。但是,有时使用简单递归同样简单(或有趣)。
我将做一些通用的例子,并使用bar(foo)
作为你的somethingHappensHere
条件的一个例子。
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
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
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)