我想概括一下这段代码,但无法以一种简洁的方式看到如何做到这一点:
defmodule Demo do
defp side_effect(bool, label) do
if bool do
IO.puts label
end
end
def go do
{a,b,c} = {4,8,13}
[2,3,4,5,7,8,9,10,11,12] # always in ascending order
|> Stream.drop_while( fn i -> bool = (i<a); side_effect(bool, "a_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<b); side_effect(bool, "b_#{i}"); bool end )
|> Stream.drop_while( fn i -> bool = (i<c); side_effect(bool, "c_#{i}"); bool end )
|> Enum.to_list
end
end
当它运行时(Demo.go)我得到:
a_2
a_3
b_4
b_5
b_7
c_8
c_9
c_10
c_11
c_12
[]
正如我所希望的那样 - 为输入列表中的每个元素执行副作用,并将空列表作为最终输出。 但是有可能对此进行概括,以便我可以以编程方式包含(基于列表)尽可能多的行,如下所示:
|> Stream.drop_while( fn i -> bool = (i<x); side_effect(bool, "x_#{i}"); bool end )
如果我能提供帮助,我希望不要探索宏。
答案 0 :(得分:2)
流是一种数据结构,这意味着您可以减少它,在每一步中将其精炼为一组特定的值:
defmodule Demo do
defp side_effect(var, threshold, label) do
if var < threshold do
IO.puts "#{label}_#{var}"
true
else
false
end
end
def go do
values = [a: 4, b: 8, c: 13]
stream =
Enum.reduce(values, [2,3,4,5,7,8,9,10,11,12], fn {k, v}, acc ->
Stream.drop_while(acc, fn i -> side_effect(i, v, k) end)
end)
Enum.to_list(stream)
end
end
您还可以探索其他解决方案。例如,您可以简单地执行筛选操作,以检查值是否小于列表中的阈值,而不是为值的每个部分创建流。像这样:
defmodule Demo do
defp side_effect(i, values) do
pair = Enum.find(values, fn {_, v} -> i < v end)
case pair do
{k, v} ->
IO.puts "#{k}_#{i}"
false
nil ->
true
end
end
def go do
values = [a: 4, b: 8, c: 13]
[2,3,4,5,7,8,9,10,11,12]
|> Stream.filter(fn i -> side_effect(i, values) end)
|> Enum.to_list()
end
end
我不确定你是否真的需要过滤。如果没有,Stream.map/2或Stream.each / 2(副作用专用)会更好。