gpt4 book ai didi

closures - 在 Elixir 中创建闭包

转载 作者:行者123 更新时间:2023-12-02 15:53:43 24 4
gpt4 key购买 nike

我有一个 Sequence 结构,它由一个 state 和一个 generator 函数组成,该函数从旧状态生成新状态。我想编写一个 limit 函数,该函数返回一个新序列,该序列应在最多和每个 n + k 次精确返回新状态 n 次它应该返回nil。到目前为止的代码是:

defmodule Sequence do
defstruct [:state, :generator]

def generate(%Sequence{state: nil}) do
nil
end

def generate(%Sequence{state: state , generator: generator } = seq) do
{old_state, new_state} = generator.(state)
{ old_state, %Sequence{ seq | state: new_state } }
end

def limit(%Sequence{ generator: generator } = seq, n) when n > -1 do
lim_gen = create_limit_gen(generator, n)
%Sequence{ seq | generator: lim_gen }
end

defp create_limit_gen(generator, n) do
lim_gen = fn
nil ->
nil
_ when n == 0 ->
nil
st ->
IO.puts(n) # no closure happens here
n = n - 1
generator.(st)
end
lim_gen
end

end

我想要得到以下结果:

iex> seq = %Sequence{state: 0, generator: &{&1, &1 + 1}} |> Sequence.limit 2
iex> {n, seq} = seq |> Sequence.generate; n
0
iex> {n, seq} = seq |> Sequence.generate; n
1
iex> seq |> Sequence.generate
nil
iex> seq = %Sequence{state: 0, generator: &{&1, nil}} |> Sequence.limit 2
iex> {n, seq} = seq |> Sequence.generate; n
0
iex> seq |> Sequence.generate
nil

问题是 IO.puts 始终打印相同的数字,这意味着它不会改变。然而,我的限制生成器取决于该值及其在闭包中的变化。这里有什么问题以及如何解决它?欢迎任何帮助:)

PS:我不允许向结构添加新字段,并且我不想使用 GenServerETS

最佳答案

在大多数情况下,创建 MCVE 来定位问题并了解发生的情况是有意义的。让我们开始吧:

iex|1 ▶ defmodule Test do
...|1 ▶ def closure(n) do
...|1 ▶ fn
...|1 ▶ _ when is_nil(n) or n == 0 -> IO.puts("NIL")
...|1 ▶ _ ->
...|1 ▶ IO.puts(n)
...|1 ▶ closure(n - 1).(n - 1) # or something else
...|1 ▶ end
...|1 ▶ end
...|1 ▶ end

好的,让我们测试一下:

iex|2 ▶ Test.closure(2).(2)  
2
1
NIL
:ok

酷,它按预期工作。现在让我们回到您的代码:

st ->
IO.puts(n) # no closure happens here
n = n - 1
generator.(st)

子句中的第二行根本没有任何作用,因为Elixir中的所有内容都是不可变的。 n = n - 1 将局部变量 n 反弹到新值,但它会立即被丢弃(GC),因为 generator 接收到 stn 不再在任何地方使用。

代码相当繁琐,但我建议你不需要在create_limit_gen中累积当前的n,你当前看到的正是闭包的工作原理: n 在创建闭包时被分配一次,并且不会随着时间的推移而改变。要更改它,应该明确地更改它,例如通过传递 n (如我的第一个 MCVE 代码片段所示。)

类似

generator.(n, create_limit_gen(generator, n - 1))

正确处理结果应该可以解决问题。

关于closures - 在 Elixir 中创建闭包,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43174241/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com