我想在 Elixir 中重写这个方法(这里用 Python 编写)
def something()
while True:
x = function()
y = function()
if x != y:
return x
function()
生成一个随机值,因此执行迟早会结束。
我的问题是以尽可能“实用的方式”翻译
while True
。
我想出了这个解决方案,但我认为可读性不太好。
def something() do
internal(function(), function())
end
defp internal(a, a) do
internal(function(), function())
end
defp internal(a, _) do
a
end
有更好的方法吗?
PS:
function()
必须在每个周期调用两次,并且不能重写。
谢谢
Elixir 也有变量和
if
表达式,所以你真正需要做的就是用递归调用替换 while True
:
def something() do
x = function()
y = function()
if x != y do
x
else
something()
end
end
递归是你的朋友
def something do
x = function()
y = function()
if x != y, do: x, else: something()
end
Stream.iterate/2
和 Stream.take_while/2
的递归答案。请注意,可以使用任何无限流生成器来代替 iterate/2
,例如。 G。 Stream.cycle/1
。
0
|> Stream.iterate(&(&1 + 1))
|> Stream.map(fn _ -> {f1(), f2()} end)
|> Stream.take_while(fn {x, y} -> x != y end)
|> Enum.to_list()
在很多情况下,这个解决方案更可靠。
我认为你的解决方案还不错,只是习惯于看到多个函数子句在起作用。您可以稍微重新排列它以使其更具可读性,但这只是个人喜好。
def something(), do: something(nil, nil)
defp something(x, x), do: something(function(), function())
defp something(x, _y), do: x
当参数相等时,
(x, x)
子句将被执行。
仅返回
(x, _y)
的 x
子句,否则将被执行。
但我不得不承认 Potibas 的答案非常简单,而且可能是一个很好的妥协。我认为我更喜欢函数子句方式一般来说,因为它使参数明确并隐藏更少的副作用。
这是一种干净的、基于流的方法,无需编写单独的函数即可实现此目的。它使用 Enum.reduce_while/3 来迭代可能无限的值序列(其具体值与我们的需求无关,我们只需要一个无限序列),并且仅在返回
{:halt, _}
元组时退出。
Enum.reduce_while(Stream.iterate(:some_value, & &1), :some_value, fn _x, _acc ->
x = function()
y = function()
if x != y,
do: {:cont, :some_value},
else: {:halt, :some_value}
end)
在上面的示例中,我使用值
:some_value
来突出显示您可以放置几乎任何您想要的值而不影响代码运行方式的情况。 (注意:{:halt, _}
元组中的第二个值将是此代码片段的返回值)
这是一个您可以在 shell 中使用的实际示例:
Enum.reduce_while(Stream.iterate(nil, & &1), [], fn _x, _acc ->
x = Enum.random(1..100)
IO.puts(x)
if x == 42,
do: {:halt, :ok},
else: {:cont, :try_again}
end)
这也可以用于处理成功/错误情况:
Enum.reduce_while(Stream.iterate(nil, & &1), [], fn _x, _acc ->
x = Enum.random(1..100)
IO.puts(x)
case x do
42 -> {:halt, {:ok, x}}
13 -> {:halt, {:error, x}}
_ -> {:cont, :try_again}
end
end)