列表:在Erlang中带有副作用的地图

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了列表:在Erlang中带有副作用的地图相关的知识,希望对你有一定的参考价值。

我有一个批量(子列表)的ID列表,我想迭代这个列表,并为批量的id中的每个id生成一个工作进程。这些工作中的每一个都将查询某些服务,获取结果并将其发送回调用者。简单来说,我想将ids列表映射到我凭借那些ids得到的数据列表。我设法实现了这个目标,但我认为,这是一种单一的方式:

lists:map(fun(Ids) ->
Pids = [spawn_link(fun() ->
    Result = [...] % Here goes a side-effect operation (http request)
    Self ! {received_data, process(Result)}
end) || Id <- Ids],
[receive {received_data, Data} -> Data end || _Pid <- Pids],
end, JobChunks)))

在这种情况下,你看到我滥用map功能,因为它的设计是无副作用。但我没有看到另一种选择。有foreach(),但它只用于运行副作用,只返回ok而在我的情况下,我也想保留列表的形状。在Haskell中有一个方便的类型类Traversabletraverse函数正是这样:运行fmap,同时允许你对每个项目执行动作(效果)。 Erlang中有类似的东西吗? (或许像smap?)。

答案

与Haskell不同的Erlang不是纯函数式编程语言。作为必然结果,它不会对功能是否能够或不会产生副作用施加限制。在Haskell中,即使I / O子系统也无法打破其纯度,这就是为什么在TraversableFunctortraversefmap)之间存在类型级别的区别,前者可以对容器的每个元素产生影响,后者可以“T。在Erlang中没有这样明显的区别,因此,你可能有一个函数execute(Container) ->,你不知道它是否会通过凝视它的签名来运行效果。这就是为什么在Erlang中使用mapsmap(或者你称之为traverse,或其他任何东西)没有任何意义并且不会带来任何价值。但确实,使用lists:map进行这种操作打破了map的契约,这应该是一个纯函数。在这种情况下,我可能会建议你使用列表理解,在我看来这是一种更惯用的方式:

[begin
    Pids = [spawn_link(fun() ->
        % Side-effect operation which worker performs
    end) || Id <- Ids],
   [receive {received_data, Data} -> Data end || _Pid <- Pids]
end || Ids <- JobChunks].

再次在我自己的观点中,副作用是列表理解和lists:map()之间的主要区别。当它们以上述方式使用时,我通常将它们视为Haskell的monad理解。

另一答案

我喜欢@Oleksandr的答案,但在列表理解中使用begin..end块感觉有点脏。我会使用函数。

同样重要的是要注意,他的答案的第二部分并不保证尊重原始列表的顺序(即它将只具有相同的元素数,但它们将根据它们到达的顺序进行排序)。这对你来说可能没问题,但如果你想能够匹配输入(Ids)和输出(结果),你必须使用选择性接收,我将在下面给你看。

所以,这就是我如何在没有OTP的情况下实现它(因为你也没有使用OTP):

your_function() ->
    [process_chunk(Ids) || Ids <- JobChunks].

process_chunk(Ids) ->
    Pids = [spawn_side_effect_fun(Id) || Id <- Ids],
    [get_result_for(Pid) || _Pid <- Pids].

spawn_side_effect_fun(Id) ->
    Self = self(),
    spawn_link(fun() ->
        Self ! {received_data, self(), your_side_effect_operation()}
    end).

get_result_for(Pid) ->
    receive
        %% Here we're pattern-matching on Pid
        %% so that we get the result for this particular Pid
        %% therefore the order is preserved in the final list.
        {received_data, Pid, Data} -> Data
    end.

注意到你没有在这里处理任何错误也很重要。由于您没有捕获退出,因此生成的进程中的错误将会破坏主要进程。

以上是关于列表:在Erlang中带有副作用的地图的主要内容,如果未能解决你的问题,请参考以下文章

translationZ 在我的带有地图片段的 ConstraintLayout 中不起作用

如何在片段中而不是在活动中使用 NavController(在片段中带有 NavHost)?

Onclicklistener 在片段列表视图中不起作用

片段实例中带有 Otto 事件总线的 IllegalArgumentException

Visual Studio 自定义代码片段在方法定义的参数列表中不起作用

在 ag-grid 中带有下拉菜单的自定义过滤器在角度 10 中不起作用