懒惰地串联一个可枚举的列表 [英] Lazily concatenate an enumerable of lists

查看:71
本文介绍了懒惰地串联一个可枚举的列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想写一个类似于List.concat/1的函数,该函数接受一个可枚举的列表,并以连续流的形式发出连接的列表.

I would like to write a function akin to List.concat/1 that takes an enumerable of lists and emits the concatenated lists as a continuous stream.

它会像这样工作:

iex> 1..3 |> Stream.map(&([&1])) |> Enum.to_list
[[1], [2], [3]]
iex> 1..3 |> Stream.map(&([&1])) |> MyStream.concat |> Enum.to_list
[1, 2, 3]

到目前为止,我想出的是:

What I have come up with so far is this:

defmodule MyStream do
  def concat(lists) do
    Enumerable.reduce(lists, [], fn(x, acc) -> acc ++ x end)
  end
end

这会产生正确的结果,但显然并不懒惰.

This produces the correct result but obviously isn't lazy.

我尝试使用Stream.Lazy失败,但实际上无法理解它的内部工作原理. Stream.Lazy的任何解释将不胜感激!

I have unsuccessfully tried using Stream.Lazy but really fail to understand the inner workings of it. Any explanation on Stream.Lazy would be greatly appreciated!

推荐答案

Elixir中的可枚举通过归约函数表示.只要您告诉我们如何简化结构,我们就可以绘制任何结构.

Enumerables in Elixir are represented via reducing functions. We can map any structure as long as you tell us how to reduce over it.

Stream的整体思想是可以组成那些归约函数.让我们以地图为例:

The whole idea of Stream is that you can compose those reducing functions. Let's take map as an example:

def map(enumerable, f) do
  Lazy[enumerable: enumerable,
       fun: fn(f1) ->
         fn(entry, acc) ->
           f1.(f.(entry), acc)
         end
       end]
end

您收到一个可枚举的对象,并且您想使用函数f映射每个元素.惰性版本接收实际的归约函数f1并返回一个新函数,该函数接收entryacc(与f1相同的参数),然后调用f.(entry)有效地映射元素,然后再调用f1(归约函数).请注意,我们是如何一一映射到元素上的.

YOu receive an enumerable and you want to map over each element with the function f. The lazy version receives the actual reducing function f1 and returns a new function, which receives entry and acc (the same arguments f1 would receive) and then call f.(entry) effectively mapping the element before you call f1 (the reducing function). Notice how we are mapping over elements one by one.

其平面图变体可能类似于:

The flat map variant of this would probably be something like:

def flat_map(enumerable, f) do
  Lazy[enumerable: enumerable,
       fun: fn(f1) ->
         fn(entry, acc) ->
           Enumerable.reduce(f.(entry), acc, f1)
         end
       end]
end

现在,每次调用f.(entry)时,都会返回一个列表,并且要遍历此新列表的每个元素,而不是遍历整个列表.

Now, every time you call f.(entry), you get a list back and you want to iterate over each element of this new list, instead of iterating over the list as a whole.

我还没有尝试过上面的代码(并且我可能错过了一些细节),但这是Streams总体上的工作方式.

I have not tried the code above (and I may have missed some detail) but that's how Streams work in general.

这篇关于懒惰地串联一个可枚举的列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆