[英]Elixir: recursive generators
Is it possible to build a Python style recursive generator with Elixir? 是否可以使用Elixir构建Python样式的递归生成器? Something like this:
像这样:
def traverse(parent_dir):
dirs, files = get_dirs_and_files_as_lists(parent_dir)
for d in dirs:
yield from traverse(d)
for f in files:
yield f
For all the files to be processed linearly, without overhead implied by an eager list of indefinite length: 对于要线性处理的所有文件,没有急切的不定长度列表所隐含的开销:
for f in traverse(dir):
process(f)
This, or some working equivalent, should be possible using streams; 使用流应该可以做到这一点或某些等效的工作。 unfortunately, I have no idea how.
不幸的是,我不知道如何。
I want something like this, just lazy: 我想要这样的东西,只是懒惰:
def traverse_eagerly(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_eagerly(x)
end
|> Enum.concat()
|> Enum.concat(files)
end
You do not need Stream
here, but if you want, here is it: 您不需要在此使用
Stream
,但是如果需要,可以使用以下代码:
defmodule Traverse do
@spec traverse(root :: binary(), yielder :: (binary() -> any())) ::
:ok | {:error, posix()}
def traverse(root, yielder) do
# https://hexdocs.pm/elixir/master/File.html?#ls/1
with {:ok, list} <- File.ls(root) do
list
|> Stream.each(fn file_or_dir ->
if File.dir?(file_or_dir),
do: traverse(file_or_dir, yielder), # TCO
else: yielder.(file_or_dir)
end)
|> Stream.run()
end
end
end
And call it like: 并这样称呼:
Traverse.traverse(".", &IO.inspect/1)
The solution appears to be trivial: replace Enum
with Stream
. 解决方案似乎很简单:用
Stream
替换Enum
。
def traverse_lazily(parent_dir) do
{dirs, files} = get_dirs_and_files_as_lists(parent_dir)
for x <- dirs do
traverse_lazily(x)
end
|> Stream.concat()
|> Stream.concat(files)
end
The following works as expected: 预期的工作如下:
s = traverse_lazily(a_dir_of_choice)
for x <- s, do: whatever_you_please(x)
Very nice of the language. 语言很好。 As fine a solution as you would wish for.
完美的解决方案,如您所愿。 Unless I'm missing something, that is :) .
除非我缺少任何东西,否则就是:)。 Comments are welcome!
欢迎发表评论!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.