我有一个Sequence结构,由一个state和一个generator函数组成,该函数从旧的生成新状态.我想写一个limit返回一个新的序列应当完全返回新的状态函数n的最大值和每一个时代n + k它应该返回时间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
Run Code Online (Sandbox Code Playgroud)
我想得到以下结果:
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
Run Code Online (Sandbox Code Playgroud)
问题是IO.puts打印总是相同的数字,这意味着它不会改变.但是我的限制生成器依赖于该值并且它在闭包中发生变化.这是什么问题,我该如何解决?欢迎任何帮助:)
PS:我不允许在结构中添加新字段,我不想使用GenServer和之类的东西ETS
在大多数情况下,创建一个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
Run Code Online (Sandbox Code Playgroud)
好的,让我们测试一下:
iex|2 ? Test.closure(2).(2)
2
1
NIL
:ok
Run Code Online (Sandbox Code Playgroud)
很酷,它按预期工作.现在让我们回到你的代码:
st ->
IO.puts(n) # no closure happens here
n = n - 1
generator.(st)
Run Code Online (Sandbox Code Playgroud)
该条款中的第二行完全没有效果,因为Elixir 中的所有内容都是不可变的.n = n - 1将局部变量n恢复为新值,但是在generator接收后立即丢弃(GC'd),因为接收st并且n不再在任何地方使用.
代码非常繁琐,但我建议您不需要累积当前n的内容create_limit_gen,您当前看到的内容恰好是闭包的工作方式:n分配一次,创建闭包时,并且它不会随时间变化.要更改它,应该明确地更改它,例如通过传递n(如我在MCVE的第一个片段中所示).
就像是
generator.(n, create_limit_gen(generator, n - 1))
Run Code Online (Sandbox Code Playgroud)
并正确处理结果应该可以解决问题.
| 归档时间: |
|
| 查看次数: |
938 次 |
| 最近记录: |